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();
}
}