控件的拖动和缩放技术全解


一、光标的指示

当光标移动到要拖动或缩放的控件上时,应显示相应的动作箭头。定义一个枚举的变量来标识对应的状态。

Enum EnumMousePointPosition

MouseSizeNone = 0 '无

MouseSizeRight = 1 '拉伸右边框

MouseSizeLeft = 2 '拉伸左边框

MouseSizeBottom = 3 '拉伸下边框

MouseSizeTop = 4 '拉伸上边框

MouseSizeTopLeft = 5 '拉伸左上角

MouseSizeTopRight = 6 '拉伸右上角

MouseSizeBottomLeft = 7 '拉伸左下角

MouseSizeBottomRight = 8 '拉伸右下角

MouseDrag = 9 '鼠标拖动

End Enum

Dim m_MousePointPosition As EnumMousePointPosition

在 MouseMove 事件中读取进入控件的光标位置,用下面函数判断光标的状态。

m_MousePointPosition = MousePointPosition(sender.Size, e)

按对应的状态显示光标形状

Select Case m_MousePointPosition

Case EnumMousePointPosition.MouseSizeNone

Me .Cursor = Cursors.Arrow '箭头

Case EnumMousePointPosition.MouseDrag

Me .Cursor = Cursors.SizeAll '四方向

Case EnumMousePointPosition.MouseSizeBottom

Me .Cursor = Cursors.SizeNS '南北

Case EnumMousePointPosition.MouseSizeTop

Me .Cursor = Cursors.SizeNS '南北

Case EnumMousePointPosition.MouseSizeLeft

Me .Cursor = Cursors.SizeWE '东西

Case EnumMousePointPosition.MouseSizeRight

Me .Cursor = Cursors.SizeWE '东西

Case EnumMousePointPosition.MouseSizeBottomLeft

Me .Cursor = Cursors.SizeNESW '东北到南西

Case EnumMousePointPosition.MouseSizeBottomRight

Me .Cursor = Cursors.SizeNWSE '东南到西北

Case EnumMousePointPosition.MouseSizeTopLeft

Me .Cursor = Cursors.SizeNWSE '东南到西北

Case EnumMousePointPosition.MouseSizeTopRight

Me .Cursor = Cursors.SizeNESW '东北到南西

End Select

如果光标离开控件, MouseMove 事件将不响应,因此用需用 MouseLeave 事件来接力完成光标状态的标识和显示。

Private Sub MyMouseLeave( ByVal sender As Object , ByVal e As System.EventArgs)

m_MousePointPosition = EnumMousePointPosition.MouseSizeNone

Me .Cursor = Cursors.Arrow

End Sub

二、拖动

拖动的原理是移动控件的 Location 到当前光标的位置,并保持控件的高度和宽度不变。如果记录起始光标点为 p ,当前光标点为 e ,那么 x 方向的移动距离是 e.X - p.X,x 方向的移动距离是 e.Y - p.Y。

在鼠标按下时,即是拖动的开始,在 MouseDown 事件中,记录光标开始拖动点

p = New Point(e.X, e.Y)

在 MouseMove 事件,检测是否持续按着鼠标左键,如果是则更新控件的起点位置

If e.Button = MouseButtons.Left Then

sender.Location = New Point(sender.Left + e.X - p.X, sender.Top + e.Y - p.Y)

End If

三、缩放

缩放的原理和拖动类似,如果缩放底边,就是根据光标的移动改变控件的高度,而不改变控件的起点位置。

同样,如果缩放底边,在鼠标按下时,即是缩放的开始,在 MouseDown 事件中,记录光标开始拖动点

p = New Point(e.X, e.Y)

在 MouseMove 事件,检测是否持续按着鼠标左键,如果是则更新控件的高度

If e.Button = MouseButtons.Left Then

sender.Size = New Size(sender.Width, sender.Height + e.Y - p1.Y)

p1 = New Point(e.X, e.Y) '记录光标拖动的当前点

End If

这里和拖动有些区别,就是高度的变化会导致光标位置数值的变化,因此需重新用 p1 定位光标起始点的位置。所有涉及控件底边和右边的缩放都要这样处理,而左边和顶边则不用。

其它所有各方向的拖动都可以类推。

四、委派

所有的操作,一共总结为三个函数, MyMouseDown,MyMouseMove,MyMouseLeave。

动态创建控件后,需委派相应的事件到这三个函数。如果创建一个按钮,

Dim Button As New Button

Controls.Add(Button)

AddHandler Button.MouseDown, AddressOf MyMouseDown

AddHandler Button.MouseMove, AddressOf MyMouseMove

AddHandler Button.MouseLeave, AddressOf MyMouseLeave

五、源码

建立一个窗体,放置一个按钮,点击该按钮创建动态建立一个可以拖动和缩放的按钮。全部源码如下:

Public Class Form1

Inherits System.Windows.Forms.Form

Enum EnumMousePointPosition

MouseSizeNone = 0 '无

MouseSizeRight = 1 '拉伸右边框

MouseSizeLeft = 2 '拉伸左边框

MouseSizeBottom = 3 '拉伸下边框

MouseSizeTop = 4 '拉伸上边框

MouseSizeTopLeft = 5 '拉伸左上角

MouseSizeTopRight = 6 '拉伸右上角

MouseSizeBottomLeft = 7 '拉伸左下角

MouseSizeBottomRight = 8 '拉伸右下角

MouseDrag = 9 '鼠标拖动

End Enum

Dim m_MousePointPosition As EnumMousePointPosition

Dim p, p1 As Point

Private Sub MyMouseDown( ByVal sender As Object , ByVal e As System.Windows.Forms.MouseEventArgs)

p = New Point(e.X, e.Y) '记录光标开始拖动点

p1 = New Point(e.X, e.Y)

End Sub

Private Sub MyMouseLeave( ByVal sender As Object , ByVal e As System.EventArgs)

m_MousePointPosition = EnumMousePointPosition.MouseSizeNone

Me .Cursor = Cursors.Arrow

End Sub

Private Sub MyMouseMove( ByVal sender As Object , ByVal e As System.Windows.Forms.MouseEventArgs)

If e.Button = MouseButtons.Left Then

Select Case m_MousePointPosition

Case EnumMousePointPosition.MouseDrag

sender.Location = New Point(sender.Left + e.X - p.X, sender.Top + e.Y - p.Y)

Case EnumMousePointPosition.MouseSizeBottom

sender.Size = New Size(sender.Width, sender.Height + e.Y - p1.Y)

p1 = New Point(e.X, e.Y) '记录光标拖动的当前点

Case EnumMousePointPosition.MouseSizeBottomRight

sender.Size = New Size(sender.Width + e.X - p1.X, sender.Height + e.Y - p1.Y)

p1 = New Point(e.X, e.Y)

Case EnumMousePointPosition.MouseSizeRight

sender.Size = New Size(sender.Width + e.X - p1.X, sender.Height)

p1 = New Point(e.X, e.Y)

Case EnumMousePointPosition.MouseSizeTop

sender.Location = New Point(sender.Left, sender.Top + (e.Y - p.Y))

sender.Size = New Size(sender.Width, sender.Height - (e.Y - p.Y))

Case EnumMousePointPosition.MouseSizeLeft

sender.Location = New Point(sender.Left + e.X - p.X, sender.Top)

sender.Size = New Size(sender.Width - (e.X - p.X), sender.Height)

Case EnumMousePointPosition.MouseSizeBottomLeft

sender.Location = New Point(sender.Left + e.X - p.X, sender.Top)

sender.Size = New Size(sender.Width - (e.X - p.X), sender.Height + e.Y - p1.Y)

p1 = New Point(e.X, e.Y)

Case EnumMousePointPosition.MouseSizeTopRight

sender.Location = New Point(sender.Left, sender.Top + (e.Y - p.Y))

sender.Size = New Size(sender.Width + (e.X - p1.X), sender.Height - (e.Y - p.Y))

p1 = New Point(e.X, e.Y)

Case EnumMousePointPosition.MouseSizeTopLeft

sender.Location = New Point(sender.Left + e.X - p.X, sender.Top + (e.Y - p.Y))

sender.Size = New Size(sender.Width - (e.X - p.X), sender.Height - (e.Y - p.Y))

End Select

Else

m_MousePointPosition = MousePointPosition(sender.Size, e) '判断光标的位置状态

Select Case m_MousePointPosition '改变光标

Case EnumMousePointPosition.MouseSizeNone

Me .Cursor = Cursors

Published At
Categories with Web编程
Tagged with
comments powered by Disqus