控制不移动拖放

时间:2014-06-30 06:47:55

标签: vb.net winforms drag-and-drop

在我的应用程序中,我想将控件移到另一侧。 tablelayoutpanel内的那个控件。我想拖动面板内的控件,面板在表格布局面板内,所以首先我删除控制表单面板,然后在表单中添加控件,然后拖动按钮控件,使问题不明显拖动。 (这意味着快速拖动它不能正常工作)。我的代码是

Private Sub HandleDraggableControlMouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Button2.MouseDown
    Dim target As Control = TryCast(sender, Control)
    Dim xWidth, xHeight As Integer

    If (Not target Is Nothing) Then

        xWidth = sender.Width
        xHeight = sender.Height
        sender.Parent.Controls.Remove(sender)
        sender.Dock = DockStyle.None

        sender.Width = xWidth
        sender.Height = xHeight
        Me.Controls.Add(sender)

        Dim pt As Point = Me.PointToClient(target.PointToScreen(Point.Empty))
        target.Location = pt
        target.Parent = Me
        target.BringToFront()
        Me.isMouseDown = True
        Me.cachedControlPos = pt
        Me.cachedMousePos = Control.MousePosition

    End If
End Sub

Private Sub HandleDraggableControlMouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Button2.MouseMove
    If (Me.isMouseDown) Then
        Dim target As Control = TryCast(sender, Control)
        If (Not target Is Nothing) Then
            Dim x As Integer = (Me.cachedControlPos.X + (Control.MousePosition.X - Me.cachedMousePos.X))
            Dim y As Integer = (Me.cachedControlPos.Y + (Control.MousePosition.Y - Me.cachedMousePos.Y))
            target.Location = New Point(x, y)

            'c2 = (c1 + (m2 - m1))

        End If
    End If
End Sub

Private Sub HandleDraggableControlMouseUp(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Button2.MouseUp
    Me.cachedControlPos = Point.Empty
    Me.cachedMousePos = Point.Empty
    Me.isMouseDown = False
End Sub

我的问题是如果快速拖动控件控件没移动光标只移动了为什么?我的编码出了什么问题?如何解决问题?

1 个答案:

答案 0 :(得分:1)

您需要将当前鼠标位置 m2 与缓存鼠标位置 m1 之间的差异添加到缓存的控件中位置 c1 为您提供当前控制位置 c2

c2 = (c1 + (m2 - m1))

这样的事情:

sender.Location = New Point(
    (cachedControlLocation.X + (e.X - startX)), 
    (cachedControlLocation.Y + (e.Y - startY))
)

这是一个示例表单,向您展示它是如何工作的:

Public Class Form1

    Public Sub New()
        Me.InitializeComponent()
        Me.ClientSize = New Size(800, 600)
        Me.panel1 = New Panel() With {.Bounds = New Rectangle(10, 10, 300, 300), .BackColor = Color.Red}
        Me.panel2 = New Panel() With {.Bounds = New Rectangle(10, 10, 200, 200), .BackColor = Color.Green}
        Me.panel3 = New Panel() With {.Bounds = New Rectangle(10, 10, 100, 100), .BackColor = Color.Blue}
        Me.panel2.Controls.Add(Me.panel3)
        Me.panel1.Controls.Add(Me.panel2)
        Me.Controls.Add(Me.panel1)
    End Sub

    Private Sub HandleDraggableControlMouseDown(sender As Object, e As MouseEventArgs) Handles panel1.MouseDown, panel2.MouseDown, panel3.MouseDown
        Dim target As Control = TryCast(sender, Control)
        If (Not target Is Nothing) Then
            Dim pt As Point = Me.PointToClient(target.PointToScreen(Point.Empty))
            target.Parent = Me
            target.BringToFront()
            target.Location = pt
            Me.isMouseDown = True
            Me.cachedControlPos = pt
            Me.cachedMousePos = Control.MousePosition
        End If
    End Sub

    Private Sub HandleDraggableControlMouseMove(sender As Object, e As MouseEventArgs) Handles panel1.MouseMove, panel2.MouseMove, panel3.MouseMove
        If (Me.isMouseDown) Then
            Dim target As Control = TryCast(sender, Control)
            If (Not target Is Nothing) Then
                Dim x As Integer = (Me.cachedControlPos.X + (Control.MousePosition.X - Me.cachedMousePos.X))
                Dim y As Integer = (Me.cachedControlPos.Y + (Control.MousePosition.Y - Me.cachedMousePos.Y))
                target.Location = New Point(x, y)

                'c2 = (c1 + (m2 - m1))

            End If
        End If
    End Sub

    Private Sub HandleDraggableControlMouseUp(sender As Object, e As MouseEventArgs) Handles panel1.MouseUp, panel2.MouseUp, panel3.MouseUp
        Me.cachedControlPos = Point.Empty
        Me.cachedMousePos = Point.Empty
        Me.isMouseDown = False
    End Sub

    Private cachedMousePos As Point
    Private cachedControlPos As Point
    Private isMouseDown As Boolean

    Private WithEvents panel1 As Panel
    Private WithEvents panel2 As Panel
    Private WithEvents panel3 As Panel

End Class

更新1

在更改父级并将其移至前面后,设置新位置非常重要。

target.Parent = Me
target.BringToFront()
target.Location = pt '<---

更新2

所以我把它缩小到造成这个问题的原因,结果证明是Selectable control style。您可以通过继承按钮类来验证这一点,并删除构造函数中的样式。

Public Class UIButton
    Inherits Button

    Public Sub New()
        MyBase.SetStyle(ControlStyles.Selectable, False)
    End Sub

End Class

那么我们如何解决这个问题呢?那么,AFAIK没有简单的解决方案。可以预期,可选择的控件将以不同于那些不能的方式处理鼠标消息。我能想到的唯一方法(也可能是一个脏的方法)是对控件进行子类化并拦截鼠标消息。以下代码不是最终解决方案,因此请谨慎使用。

Public Class UIButton
    Inherits Button

    Protected Overrides Sub WndProc(ByRef m As Message)
        Select Case m.Msg
            Case WM.LBUTTONDOWN
                Dim dw As New DWORD With {.value = m.LParam}
                Dim vk As Integer = m.WParam.ToInt32()
                MyBase.OnMouseDown(New MouseEventArgs(Windows.Forms.MouseButtons.Left, 0, dw.loword, dw.hiword, 0))
                Debug.WriteLine("X={0}, Y={1}", dw.loword, dw.hiword)
                Exit Select
            Case WM.MOVE
                Dim dw As New DWORD With {.value = m.LParam}
                Dim vk As Integer = m.WParam.ToInt32()
                If (vk = Keys.LButton) Then
                    MyBase.OnMouseMove(New MouseEventArgs(Windows.Forms.MouseButtons.Left, 0, dw.loword, dw.hiword, 0))
                    Debug.WriteLine("X={0}, Y={1}", dw.loword, dw.hiword)
                End If
                Exit Select
            Case WM.LBUTTONUP
                Dim dw As New DWORD With {.value = m.LParam}
                Dim vk As Integer = m.WParam.ToInt32()
                MyBase.OnMouseUp(New MouseEventArgs(Windows.Forms.MouseButtons.Left, 0, dw.loword, dw.hiword, 0))
                Debug.WriteLine("X={0}, Y={1}", dw.loword, dw.hiword)
                Exit Select
        End Select
        MyBase.WndProc(m)
    End Sub

    Private Enum WM As Integer
        MOVE = &H200
        LBUTTONDOWN = &H201
        LBUTTONUP = &H202
    End Enum

    <StructLayout(LayoutKind.Explicit)> _
    Private Structure DWORD
        <FieldOffset(0)> Public value As Integer
        <FieldOffset(0)> Public loword As Short
        <FieldOffset(2)> Public hiword As Short
    End Structure

End Class