WinForm制作滑动框,实现滚动相册效果

2022-06-14 09:27:52

WinForm制作滑动框,实现鼠标滚动查看效果

    界面层级:

 代码实现:

  public partial class Form1 : Form
    {
        // 初始时滑动面板所在高度Y
        private int initPanelY;

        // 鼠标松开时计算得到的滑动速度
        private double speed = 0;
        // 鼠标按下时得到的指针位置
        private int preCursorY = 0;
        // 鼠标按下的时间
        private DateTime pretime;
        //  鼠标松开的时间
        private DateTime curtime;
        // 上一次的鼠标位置
        private Point prePt;

        // tick间隔(0.02s一次)
        private int interval = 20;
        // 剩余Tick次数
        private int remainTickTime = 0;

        public Form1()
        {
            InitializeComponent();

            initPanelY = ScrollPanel.Location.Y;
            this.vScrollBar.Scroll += new System.Windows.Forms.ScrollEventHandler(this.ScrollBar_Scroll);
            ScrollPanel.MouseWheel += new MouseEventHandler(this.ScrollPanel_MouseWheel);
            ScrollPanel.MouseDown += new MouseEventHandler(this.ScrollPanel_MouseDown);
            ScrollPanel.MouseUp += new MouseEventHandler(this.ScrollPanel_MouseUp);
            ScrollPanel.MouseMove += new MouseEventHandler(this.ScrollPanel_MouseMove);

            InitTimer();
        }

        /// <summary>
        /// 鼠标按下滑动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScrollPanel_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                int px = Cursor.Position.X - prePt.X;
                int py = Cursor.Position.Y - prePt.Y;
                ScrollPanel.Location = new Point(ScrollPanel.Location.X, ScrollPanel.Location.Y + py);
                prePt = Cursor.Position;

                ControlVerticalShowRegion();
            }
        }

        /// <summary>
        ///  将滑动面板控制在父面板显示区域内( Y方向)
        /// </summary>
        private void ControlVerticalShowRegion()
        {
            if (ScrollPanel.Height > BackPanel.Height)
            {
                // 滑到顶部,归位
                if (ScrollPanel.Location.Y > initPanelY)
                {
                    ScrollPanel.Location = new Point(ScrollPanel.Location.X, initPanelY);
                    timer1.Enabled = false;
                    timer1.Stop();
                }
                // 滑到底部了,归位(y减高差)
                if (initPanelY + BackPanel.Height > ScrollPanel.Location.Y + ScrollPanel.Height)
                {
                    ScrollPanel.Location = new Point(ScrollPanel.Location.X, initPanelY - (ScrollPanel.Height - BackPanel.Height));
                    timer1.Enabled = false;
                    timer1.Stop();
                }
                // 高差
                int heightDif = ScrollPanel.Height - BackPanel.Height;
                // panel 垂直滚动范围
                int value = -ScrollPanel.Location.Y;
                double diff = (double)vScrollBar.Maximum - (double)vScrollBar.LargeChange;
                double per = value / diff;
                double p = (double)value / (double)heightDif;
                // 更新滑动条
                vScrollBar.Value = (int)(p * 100);
            }
        }

        /// <summary>
        /// 鼠标悬浮滚动
        /// </summary>
        private void ScrollPanel_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            // 滚动速度
            int scrollSpeed = 20;
            if (ScrollPanel.Height > BackPanel.Height)
            {
                ControlVerticalShowRegion();

                int delta = (e.Delta / Math.Abs(e.Delta)) * scrollSpeed;
                ScrollPanel.Location = new Point(ScrollPanel.Location.X, ScrollPanel.Location.Y + delta);
            }
        }

        /// <summary>
        /// 松开左键
        /// </summary>
        private void ScrollPanel_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                curtime = DateTime.Now;

                int curPanelY = Cursor.Position.Y;
                // 速度 = 距离 /  时间
                int dis = curPanelY - preCursorY;
                double seconds = (curtime - pretime).TotalMilliseconds;
                speed = (double)dis / seconds;
                // 持续时间
                double durTime = Math.Abs(speed);
                // 总tick次数 = 总共持续时间 durTime*1000 毫秒 / Tick间隔 interval=20
                // 总tick次数
                int tickTime = (int)((durTime * 1000) / interval);
                remainTickTime = tickTime;

                timer1.Interval = interval;
                timer1.Enabled = true;
                timer1.Start();
            }
        }

        /// <summary>
        /// 初始化计时器
        /// </summary>
        private void InitTimer()
        {
            timer1.Interval = interval;
            timer1.Tick += new EventHandler(Timer1_Tick);
        }

        private void Timer1_Tick(object sender, EventArgs e)
        {
            remainTickTime--;
            if (remainTickTime <= 0)
            {
                timer1.Enabled = false;
                timer1.Stop();
                return;
            }
            // 根据拟合函数 得到y
            double deltaY = EasingCurve(remainTickTime, 0.001);
            int delta = (int)(speed > 0 ? deltaY : -deltaY);

            ScrollPanel.Location = new Point(ScrollPanel.Location.X, ScrollPanel.Location.Y + delta);
            ControlVerticalShowRegion();
        }

        // 拟合曲线 y = x ^ 2[0, durTime],在区间 [ 0, durTime ] 上均匀散列x,随x的等值递减y值加速递减
        /*
        *               |              /
        *               |             /
        *               |            /
        *               |          /
        *               |        /
        *               |     /
        *               |  /
        *               |__________________________________
        *             0     <—   tickTime (tick次数)
        */
        /// <summary>
        /// 自定义缓动曲线  (本例使用二次函数,当然还有其他更好的拟合数学模型)
        /// </summary>
        private double EasingCurve(double x, double scaleFactor)
        {
            // y=x^2  二次函数
            return x * x * scaleFactor;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 开始加载Form时设置panel高度,可动态为其添加子元素
            ScrollPanel.Height = 800;
            // ...
        }

        /// <summary>
        /// 滚动条事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            if (ScrollPanel.Height > BackPanel.Height)
            {
                //  滑动条滚动
                int heightDif = ScrollPanel.Height - BackPanel.Height;
                double percent = (double)heightDif / (double)vScrollBar.Maximum;
                double percen = (double)heightDif / ((double)vScrollBar.Maximum - (double)vScrollBar.LargeChange);
                double value = (double)vScrollBar.Value * percen;

                int y = initPanelY - (int)value;
                ScrollPanel.Location = new Point(ScrollPanel.Location.X, y);
            }
        }

        /// <summary>
        /// 鼠标按下
        /// </summary>
        private void ScrollPanel_MouseDown(object sender, MouseEventArgs e)
        {
            prePt = Cursor.Position;
            preCursorY = Cursor.Position.Y;
            pretime = DateTime.Now;

            //timer1.Interval = 5000;
            timer1.Enabled = false;
            timer1.Stop();
        }

    }

  • 作者:Pai大星
  • 原文链接:https://blog.csdn.net/qq_38190993/article/details/98855914
    更新时间:2022-06-14 09:27:52