在网上搜索文章后,我想出了一个基于 winforms 的触摸屏应用程序的设计,该应用程序需要像智能手机一样滚动。该应用程序本身将在平板电脑、笔记本电脑或触摸屏台式机上运行。
现在我陷入了有趣的部分。我想我必须处理面板上的 mousedown、mouseup 和 mousemove 来设置自动滚动位置,这样当有人触摸面板并拖动时,它就会发挥滚动魔法。请帮助填写下面方法存根中的几行代码。关于自动滚动位置的 msdn doc 非常令人困惑,因为它返回负数,但需要使用 abs 等设置为正数。
Point mouseDownPoint;
Point mouseUpPoint;
Point mouseDragPoint;
private void myPanel_MouseDown(object sender, MouseEventArgs e)
{
this.mouseDownPoint = e.Location;
Console.WriteLine("Mouse down at {0}", e.location);
}
private void myPanel_MouseUp(object sender, MouseEventArgs e)
{
this.mouseUpPoint = e.Location;
this.mouseDownPoint = new Point(); //will set for IsEmpty check
Console.WriteLine("Mouse Up at {0}", e.location);
}
private void myPanel_MouseMove(object sender, MouseEventArgs e)
{
Console.WriteLine("Mouse at {0}", e.location);
if (mouseDownPoint.IsEmpty()) //finger is off the touchscreen
return;
myPanel.Autocrollposition = ??
}
谢谢你
//更新 - 下面我有经过反复试验和测试的代码。 (未重构)。如果有人有更优雅的解决方案,请发布。
Point mouseDownPoint;
private void innerpanel_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
this.mouseDownPoint = e.Location;
}
private void innerpanel_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
if ((mouseDownPoint.X == e.Location.X) && (mouseDownPoint.Y == e.Location.Y))
return;
Point currAutoS = innerpanel.AutoScrollPosition;
if (mouseDownPoint.Y > e.Location.Y)
{
//finger slide UP
if (currAutoS.Y != 0)
currAutoS.Y = Math.Abs(currAutoS.Y) - 5;
}
else if (mouseDownPoint.Y < e.Location.Y)
{
//finger slide down
currAutoS.Y = Math.Abs(currAutoS.Y) + 5;
}
else
{
currAutoS.Y = Math.Abs(currAutoS.Y);
}
if (mouseDownPoint.X > e.Location.X)
{
//finger slide left
if (currAutoS.X != 0)
currAutoS.X = Math.Abs(currAutoS.X) - 5;
}
else if (mouseDownPoint.X < e.Location.X)
{
//finger slide right
currAutoS.X = Math.Abs(currAutoS.X) + 5;
}
else
{
currAutoS.X = Math.Abs(currAutoS.X);
}
innerpanel.AutoScrollPosition = currAutoS;
mouseDownPoint = e.Location; //IMPORTANT
}
作为一个组件:
public partial class TouchableFlowLayoutPanel : FlowLayoutPanel
{
private bool _doTouchScroll;
private Point _mouseStartPoint = Point.Empty;
private Point _panelStartPoint = Point.Empty;
/// <summary>
/// Initializes a new instance of the <see cref="TouchableFlowLayoutPanel" /> class.
/// </summary>
public TouchableFlowLayoutPanel()
{
InitializeComponent();
Program.mouseFilter.MouseFilterDown += mouseFilter_MouseFilterDown;
Program.mouseFilter.MouseFilterMove += mouseFilter_MouseFilterMove;
Program.mouseFilter.MouseFilterUp += mouseFilter_MouseFilterUp;
}
/// <summary>
/// Initializes a new instance of the <see cref="TouchableFlowLayoutPanel" /> class.
/// </summary>
/// <param name="container">The container.</param>
public TouchableFlowLayoutPanel(IContainer container)
{
container.Add(this);
InitializeComponent();
Program.mouseFilter.MouseFilterDown += mouseFilter_MouseFilterDown;
Program.mouseFilter.MouseFilterMove += mouseFilter_MouseFilterMove;
Program.mouseFilter.MouseFilterUp += mouseFilter_MouseFilterUp;
}
/// <summary>
/// Handles the MouseFilterDown event of the mouseFilter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="MouseFilterEventArgs" /> instance containing the event data.
/// </param>
private void mouseFilter_MouseFilterDown(object sender, MouseFilterEventArgs e)
{
if (!_doTouchScroll && e.Button == MouseButtons.Left)
{
_mouseStartPoint = new Point(e.X, e.Y);
_panelStartPoint = new Point(-AutoScrollPosition.X,
-AutoScrollPosition.Y);
}
}
/// <summary>
/// Handles the MouseFilterMove event of the mouseFilter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="MouseFilterEventArgs" /> instance containing the event data.
/// </param>
private void mouseFilter_MouseFilterMove(object sender, MouseFilterEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (!_mouseStartPoint.Equals(Point.Empty))
{
int dx = (e.X - _mouseStartPoint.X);
int dy = (e.Y - _mouseStartPoint.Y);
if (_doTouchScroll)
{
AutoScrollPosition = new Point(_panelStartPoint.X - dx,
_panelStartPoint.Y - dy);
}
else if (Math.Abs(dx) > 10 || Math.Abs(dy) > 10)
{
_doTouchScroll = true;
}
}
}
}
/// <summary>
/// Handles the MouseFilterUp event of the mouseFilter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="MouseFilterEventArgs" /> instance containing the event data.
/// </param>
private void mouseFilter_MouseFilterUp(object sender, MouseFilterEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (_doTouchScroll && !AutoScrollPosition.Equals(_panelStartPoint) &&
!_panelStartPoint.Equals(Point.Empty))
{
// don't fire Click-Event
e.Handled = true;
}
_doTouchScroll = false;
_mouseStartPoint = Point.Empty;
_panelStartPoint = Point.Empty;
}
}
}
internal class MouseFilter : IMessageFilter
{
private const int WM_LBUTTONDOWN = 0x0201;
private const int WM_LBUTTONUP = 0x0202;
private const int WM_MOUSEMOVE = 0x0200;
/// <summary>
/// Filters a message before sending it
/// </summary>
/// <param name="m">The message to be sent.This message can not be changed.</param>
/// <returns>
/// true to filter the message and prevent it from being sent. false to allow the message to be sent to the next filter or control.
/// </returns>
public bool PreFilterMessage(ref Message m)
{
Point mousePosition = Control.MousePosition;
var args = new MouseFilterEventArgs(MouseButtons.Left, 0, mousePosition.X, mousePosition.Y, 0);
switch (m.Msg)
{
case WM_MOUSEMOVE:
if (MouseFilterMove != null)
{
MouseFilterMove(Control.FromHandle(m.HWnd), args);
}
break;
case WM_LBUTTONDOWN:
if (MouseFilterDown != null)
{
MouseFilterDown(Control.FromHandle(m.HWnd), args);
}
break;
case WM_LBUTTONUP:
if (MouseFilterUp != null)
{
MouseFilterUp(Control.FromHandle(m.HWnd), args);
}
break;
}
// Always allow message to continue to the next filter control
return args.Handled;
}
/// <summary>
/// Occurs when [mouse filter up].
/// </summary>
public event MouseFilterEventHandler MouseFilterUp;
/// <summary>
/// Occurs when [mouse filter down].
/// </summary>
public event MouseFilterEventHandler MouseFilterDown;
/// <summary>
/// Occurs when [mouse filter move].
/// </summary>
public event MouseFilterMoveEventHandler MouseFilterMove;
}
internal delegate void MouseFilterEventHandler(object sender, MouseFilterEventArgs args);
internal delegate void MouseFilterMoveEventHandler(object sender, MouseFilterEventArgs args);
internal class MouseFilterEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MouseFilterEventArgs" /> class.
/// </summary>
/// <param name="mouseButton">The mouse button.</param>
/// <param name="clicks">The clicks.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="delta">The delta.</param>
public MouseFilterEventArgs(MouseButtons mouseButton, int clicks, int x, int y, int delta)
{
Button = mouseButton;
Clicks = clicks;
X = x;
Y = y;
Delta = delta;
Handled = false;
}
/// <summary>
/// Gets or sets the button.
/// </summary>
/// <value>
/// The button.
/// </value>
public MouseButtons Button { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="MouseFilterEventArgs" /> is handled.
/// </summary>
/// <value>
/// <c>true</c> if handled; otherwise, <c>false</c>.
/// </value>
public bool Handled { get; set; }
/// <summary>
/// Gets or sets the X.
/// </summary>
/// <value>
/// The X.
/// </value>
public int X { get; set; }
/// <summary>
/// Gets or sets the Y.
/// </summary>
/// <value>
/// The Y.
/// </value>
public int Y { get; set; }
/// <summary>
/// Gets or sets the clicks.
/// </summary>
/// <value>
/// The clicks.
/// </value>
public int Clicks { get; set; }
/// <summary>
/// Gets or sets the delta.
/// </summary>
/// <value>
/// The delta.
/// </value>
public int Delta { get; set; }
}
static class Program
{
public static MouseFilter mouseFilter = new MouseFilter();
/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>
[STAThread]
static void Main()
{
Application.AddMessageFilter(mouseFilter);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
7 年后,但对于任何正在寻找整洁的 winforms 解决方案的人来说:
using System;
using System.Drawing;
using System.Windows.Forms;
/// <summary>
/// Pass the panel into constructor and the control will be turned into a touch scrollable control.
/// </summary>
public class TouchScroll
{
private Point mouseDownPoint;
private Panel parentPanel;
/// <summary>
/// pass in the panel you would like to be touch scrollable and it will be handled here.
/// </summary>
/// <param name="panel">The root panel you need to scroll with</param>
public TouchScroll(Panel panel)
{
parentPanel = panel;
AssignEvents(panel);
}
private void AssignEvents(Control control)
{
control.MouseDown += MouseDown;
control.MouseMove += MouseMove;
foreach (Control child in control.Controls)
AssignEvents(child);
}
private void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
this.mouseDownPoint = Cursor.Position;
}
private void MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
Point pointDifference = new Point(Cursor.Position.X - mouseDownPoint.X, Cursor.Position.Y - mouseDownPoint.Y);
if ((mouseDownPoint.X == Cursor.Position.X) && (mouseDownPoint.Y == Cursor.Position.Y))
return;
Point currAutoS = parentPanel.AutoScrollPosition;
parentPanel.AutoScrollPosition = new Point(Math.Abs(currAutoS.X) - pointDifference.X, Math.Abs(currAutoS.Y) - pointDifference.Y);
mouseDownPoint = Cursor.Position; //IMPORTANT
}
}
}
这是我使用 IMessageFilter 的方式。对于每个正在寻找解决方案的人。 首先,您必须实现一个将侦听所有应用程序事件的过滤器:
internal class MouseFilter : IMessageFilter
{
private const int WM_LBUTTONDOWN = 0x0201;
private const int WM_LBUTTONUP = 0x0202;
private const int WM_MOUSEMOVE = 0x0200;
/// <summary>
/// Filtert eine Meldung, bevor sie gesendet wird.
/// </summary>
/// <param name="m">Die zu sendende Meldung. Diese Meldung kann nicht geändert werden.</param>
/// <returns>
/// true, um die Meldung zu filtern und das Senden zu verhindern. false, um das Senden der Meldung bis zum nächsten Filter oder Steuerelement zu ermöglichen.
/// </returns>
public bool PreFilterMessage(ref Message m)
{
Point mousePosition = Control.MousePosition;
var args = new MouseFilterEventArgs(MouseButtons.Left, 0, mousePosition.X, mousePosition.Y, 0);
switch (m.Msg)
{
case WM_MOUSEMOVE:
if (MouseFilterMove != null)
{
MouseFilterMove(Control.FromHandle(m.HWnd), args);
}
break;
case WM_LBUTTONDOWN:
if (MouseFilterDown != null)
{
MouseFilterDown(Control.FromHandle(m.HWnd), args);
}
break;
case WM_LBUTTONUP:
if (MouseFilterUp != null)
{
MouseFilterUp(Control.FromHandle(m.HWnd), args);
}
break;
}
// Always allow message to continue to the next filter control
return args.Handled;
}
/// <summary>
/// Occurs when [mouse filter up].
/// </summary>
public event MouseFilterEventHandler MouseFilterUp;
/// <summary>
/// Occurs when [mouse filter down].
/// </summary>
public event MouseFilterEventHandler MouseFilterDown;
/// <summary>
/// Occurs when [mouse filter move].
/// </summary>
public event MouseFilterMoveEventHandler MouseFilterMove;
}
internal delegate void MouseFilterEventHandler(object sender, MouseFilterEventArgs args);
internal delegate void MouseFilterMoveEventHandler(object sender, MouseFilterEventArgs args);
internal class MouseFilterEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MouseFilterEventArgs" /> class.
/// </summary>
/// <param name="mouseButton">The mouse button.</param>
/// <param name="clicks">The clicks.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="delta">The delta.</param>
public MouseFilterEventArgs(MouseButtons mouseButton, int clicks, int x, int y, int delta)
{
Button = mouseButton;
Clicks = clicks;
X = x;
Y = y;
Delta = delta;
Handled = false;
}
/// <summary>
/// Gets or sets the button.
/// </summary>
/// <value>
/// The button.
/// </value>
public MouseButtons Button { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="MouseFilterEventArgs" /> is handled.
/// </summary>
/// <value>
/// <c>true</c> if handled; otherwise, <c>false</c>.
/// </value>
public bool Handled { get; set; }
/// <summary>
/// Gets or sets the X.
/// </summary>
/// <value>
/// The X.
/// </value>
public int X { get; set; }
/// <summary>
/// Gets or sets the Y.
/// </summary>
/// <value>
/// The Y.
/// </value>
public int Y { get; set; }
/// <summary>
/// Gets or sets the clicks.
/// </summary>
/// <value>
/// The clicks.
/// </value>
public int Clicks { get; set; }
/// <summary>
/// Gets or sets the delta.
/// </summary>
/// <value>
/// The delta.
/// </value>
public int Delta { get; set; }
}
然后您必须将此过滤器注册到您的程序中:
static class Program
{
public static MouseFilter mouseFilter = new MouseFilter();
/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>
[STAThread]
static void Main()
{
Application.AddMessageFilter(mouseFilter);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
现在您可以监听全局鼠标事件并滚动可滚动面板,如下所示:
public partial class MainForm : Form
{
private bool _doTouchScroll;
private Point _mouseStartPoint = Point.Empty;
private Point _yourScrollablePanelStartPoint = Point.Empty;
/// <summary>
/// Initializes a new instance of the <see cref="MainForm" /> class.
/// </summary>
public MainForm()
{
InitializeComponent();
Program.mouseFilter.MouseFilterDown += mouseFilter_MouseFilterDown;
Program.mouseFilter.MouseFilterMove += mouseFilter_MouseFilterMove;
Program.mouseFilter.MouseFilterUp += mouseFilter_MouseFilterUp;
}
/// <summary>
/// Handles the MouseFilterDown event of the mudmFilter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="MouseFilterEventArgs" /> instance containing the event data.
/// </param>
private void mouseFilter_MouseFilterDown(object sender, MouseFilterEventArgs e)
{
if (!_doTouchScroll && e.Button == MouseButtons.Left)
{
_mouseStartPoint = new Point(e.X, e.Y);
_yourScrollablePanelStartPoint = new Point(-yourScrollablePanel.AutoScrollPosition.X,
-yourScrollablePanel.AutoScrollPosition.Y);
}
}
/// <summary>
/// Handles the MouseFilterMove event of the mudmFilter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="MouseFilterEventArgs" /> instance containing the event data.
/// </param>
private void mouseFilter_MouseFilterMove(object sender, MouseFilterEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (!_mouseStartPoint.Equals(Point.Empty))
{
int dx = (e.X - _mouseStartPoint.X);
int dy = (e.Y - _mouseStartPoint.Y);
if (_doTouchScroll)
{
yourScrollablePanel.AutoScrollPosition = new Point(_yourScrollablePanelStartPoint.X - dx,
_yourScrollablePanelStartPoint.Y - dy);
}
else if (Math.Abs(dx) > 10 || Math.Abs(dy) > 10)
{
_doTouchScroll = true;
}
}
}
}
/// <summary>
/// Handles the MouseFilterUp event of the mudmFilter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="MouseFilterEventArgs" /> instance containing the event data.
/// </param>
private void mouseFilter_MouseFilterUp(object sender, MouseFilterEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (_doTouchScroll && !yourScrollablePanel.AutoScrollPosition.Equals(_yourScrollablePanelStartPoint) &&
!_yourScrollablePanelStartPoint.Equals(Point.Empty))
{
// dont fire Click-Event
e.Handled = true;
}
_doTouchScroll = false;
_mouseStartPoint = Point.Empty;
_yourScrollablePanelStartPoint = Point.Empty;
}
}
}
我使用了OP发布的代码,但发现如果面板中有标签之类的东西,它就不起作用。为了让这项工作更顺利我改变了。
e.Location
到
PointToClient(Cursor.Position)
然后面板内的所有对象也调用 mousedown 和 mousemove 事件。这样,无论您单击哪里,它都应该移动。
对于原来的帖子,考虑廉价葬礼的答案。
这个版本更简单,触感更流畅(考虑了手指移动速度,但没有考虑移开手指后仍然滚动的效果,就像移动但速度减慢(也许我有时间就会这么做)
适用于面板或 FlowLayoutPanel
创建一个表单并在其上插入 FlowLayoutPanel。
表格代码:
Public Class Form1
Private Function GenerateButton(pName As String) As Button
Dim mResult As New Button
With mResult
.Name = pName
.Text = pName
.Width = FlowPanel.Width
.Height = 100
.Margin = New Padding(0)
.Padding = New Padding(0)
.BackColor = Color.CornflowerBlue
AddHandler .MouseDown, AddressOf Button_MouseDown
AddHandler .MouseMove, AddressOf Button_MouseMove
End With
Return mResult
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
FlowPanel.Padding = New Padding(0)
FlowPanel.Margin = New Padding(0)
Dim i As Integer
For i = 1 To 100
FlowPanel.Controls.Add(GenerateButton("btn" & i.ToString))
Next
End Sub
Dim myMouseDownPoint As Point
Dim myCurrAutoSMouseDown As Point
Private Sub Button_MouseDown(sender As Object, e As MouseEventArgs) Handles FlowPanel.MouseDown
myMouseDownPoint = PointToClient(Cursor.Position)
myCurrAutoSMouseDown = FlowPanel.AutoScrollPosition
End Sub
Private Sub Button_MouseMove(sender As Object, e As MouseEventArgs) Handles FlowPanel.MouseMove
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim mLocation As Point = PointToClient(Cursor.Position)
If myMouseDownPoint <> mLocation Then
Dim mCurrAutoS As Point
Dim mDeslocation As Point = myMouseDownPoint - mLocation
mCurrAutoS.X = Math.Abs(myCurrAutoSMouseDown.X) + mDeslocation.X
mCurrAutoS.Y = Math.Abs(myCurrAutoSMouseDown.Y) + mDeslocation.Y
FlowPanel.AutoScrollPosition = mCurrAutoS
End If
End If
End Sub
提示: 要隐藏 flowlayoutpanel(或面板)的滚动条,请创建一个继承自 flowlayoutpanel(或面板)的用户控件,并且:
Imports System.Runtime.InteropServices
Public Class FlowLayoutPanelExt
Inherits FlowLayoutPanel
<DllImport("user32.dll")> _
Private Shared Function ShowScrollBar(hWnd As IntPtr, wBar As Integer, bShow As Boolean) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
Private Enum ScrollBarDirection
SB_HORZ = 0
SB_VERT = 1
SB_CTL = 2
SB_BOTH = 3
End Enum
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If Me.Visible Then
ShowScrollBar(Me.Handle, CInt(ScrollBarDirection.SB_BOTH), False)
MyBase.WndProc(m)
End If
End Sub
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.AutoScroll = True
End Sub
End Class
感谢 Tom Hobson 的回答,我已将其修改为自动为所有子控件及其子控件分配事件
注意:此滚动仅适用于 Y 轴,您可以看到 Wei Chun 评论使其适用于 X 轴
这是完整代码
internal class ACTouchPanel : Panel
{
private Point mouseDownPoint;
public ACTouchPanel()
{
this.MouseDown += ACTouchPanel_MouseDown;
this.MouseMove += ACTouchPanel_MouseMove;
this.ControlAdded += ACTouchPanel_ControlAdded;
}
private void ACTouchPanel_ControlAdded(object sender, ControlEventArgs e)
{
AssignEvents(e.Control);
}
private void AssignEvents(Control control)
{
control.MouseDown += ACTouchPanel_MouseDown;
control.MouseMove += ACTouchPanel_MouseMove;
foreach (Control child in control.Controls)
AssignEvents(child);
}
private void ACTouchPanel_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
this.mouseDownPoint = Cursor.Position;
}
private void ACTouchPanel_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
Point pointDifference = new Point(Cursor.Position.X - mouseDownPoint.X, Cursor.Position.Y - mouseDownPoint.Y);
if ((mouseDownPoint.X == Cursor.Position.X) && (mouseDownPoint.Y == Cursor.Position.Y))
return;
Point currAutoS = this.AutoScrollPosition;
this.AutoScrollPosition = new Point(Math.Abs(currAutoS.X) - pointDifference.X, Math.Abs(currAutoS.Y) - pointDifference.Y);
mouseDownPoint = Cursor.Position; //IMPORTANT
}
}
此解决方案似乎是最好的解决方案,也是最普遍接受的解决方案 - 但是,如果您滚动到底部并触摸按钮后面的实际流量控制(我试图这样做,以便有空白空间),然后,您必须双击并按住该按钮才能恢复滚动。重新启动应用程序将恢复类似电话的滚动功能。我想知道是否有其他人看到过这一点或弄清楚了 - 用您的应用程序尝试一下,看看是否也是如此。我修改了上面的代码片段,以便您可以启动一个新项目,将其复制并粘贴到 form1 的代码中,然后单击运行。
Public Class Form1
Dim FlowPanel As New FlowLayoutPanel
Private Function GenerateButton(ByVal pName As String) As Button
Dim mResult As New Button
With mResult
.Name = pName
.Text = pName
.Width = 128
.Height = 128
.Margin = New Padding(0)
.Padding = New Padding(0)
.BackColor = Color.CornflowerBlue
AddHandler .MouseDown, AddressOf Button_MouseDown
AddHandler .MouseMove, AddressOf Button_MouseMove
End With
Return mResult
End Function
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
Me.Width = 806
Me.Height = 480
FlowPanel.Padding = New Padding(0)
FlowPanel.Margin = New Padding(0)
' FlowPanel.ColumnCount = Me.Width / (128 + 6)
FlowPanel.Dock = DockStyle.Fill
FlowPanel.AutoScroll = True
Me.Controls.Add(FlowPanel)
Dim i As Integer
For i = 1 To 98
FlowPanel.Controls.Add(GenerateButton("btn" & i.ToString))
Next
End Sub
Dim myMouseDownPoint As Point
Dim myCurrAutoSMouseDown As Point
Private Sub Button_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
myMouseDownPoint = PointToClient(Cursor.Position)
myCurrAutoSMouseDown = FlowPanel.AutoScrollPosition
End Sub
Private Sub Button_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim mLocation As Point = PointToClient(Cursor.Position)
If myMouseDownPoint <> mLocation Then
Dim mCurrAutoS As Point
Dim mDeslocation As Point = myMouseDownPoint - mLocation
mCurrAutoS.X = Math.Abs(myCurrAutoSMouseDown.X) + mDeslocation.X
mCurrAutoS.Y = Math.Abs(myCurrAutoSMouseDown.Y) + mDeslocation.Y
FlowPanel.AutoScrollPosition = mCurrAutoS
End If
End If
End Sub
End Class