(解答)Formコントロールのドラッグドロップによる移動

タグの編集
投稿者 葉月  (社会人) 投稿日時 2012/1/14 17:14:24
質問ではありません。
Labelのドラッグドロップによる移動の質問が、趣旨の違うスレッド
であったためスレッドを分けました。
サンプルは、次の回答に載せます。

■元のスレッド
http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=10651

>補足
Formのコントロールであれば、基本同じやり方で移動ができます。
以上の経緯からタイトルをコントロールのドラッグドロップによる
移動にしています。

>pawaさん
コントロールのドラッグドロップの移動に関して不明点がありましたら、
こちらにレスしてください。
投稿者 葉月  (社会人) 投稿日時 2012/1/14 17:17:15
>サンプル
' 実際は、移動というより座標の入れ替えを行っています。
Public Class Form1

    Private flgMouseDown As Boolean = False
    ' マウスが押された時のLabel1の座標 
    Private movedPoint As Point

    Private Sub Form1_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
        Me.Label1.Text = "動くラベル"
        Me.Label1.Font = New System.Drawing.Font("MS UI Gothic", 18.0!, System.Drawing.FontStyle.Regular, _
                                                 System.Drawing.GraphicsUnit.Point, CType(128, Byte))
        Me.Label1.BorderStyle = BorderStyle.FixedSingle
    End Sub

    Private Sub Label1_MouseDown(ByVal sender As System.ObjectByVal e As System.Windows.Forms.MouseEventArgs) Handles Label1.MouseDown

        If (Me.flgMouseDown) Then
            Return
        End If

        Me.flgMouseDown = True
        ' マウスを押したときの座標 
        Me.movedPoint = e.Location

        'Console.WriteLine("MouseDown") 
    End Sub

    Private Sub Label1_MouseUp(ByVal sender As System.ObjectByVal e As System.Windows.Forms.MouseEventArgs) Handles Label1.MouseUp
        Me.flgMouseDown = False
        'Console.WriteLine("MouseUp") 
    End Sub

    Private Sub Label1_MouseMove(ByVal sender As System.ObjectByVal e As System.Windows.Forms.MouseEventArgs) Handles Label1.MouseMove

        If Not Me.flgMouseDown Then
            Return
        End If

        Dim p As Point = Me.Label1.Parent.PointToClient(Cursor.Position)
        Me.Label1.Location = New Point(p.X - Me.movedPoint.X, p.Y - Me.movedPoint.Y)

        'Console.WriteLine("MouseMove") 
    End Sub
End Class


投稿者 葉月  (社会人) 投稿日時 2012/2/7 23:59:41
コントロールが複数の場合

Public Class Form1

    ' マウスが押された時の各Labelの座標 
    Private dictMovedPoints As Dictionary(Of Label, Point)
    Private dictFlgMouseDowns As Dictionary(Of Label, Boolean)

    Sub New()

        ' この呼び出しはデザイナーで必要です。 
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。 

        Me.dictMovedPoints = New Dictionary(Of Label, Point)
        Me.dictFlgMouseDowns = New Dictionary(Of Label, Boolean)
    End Sub


    Private Sub Form1_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
        ' ラベル 
        Dim lbls As Label() = {Me.Label1, Me.Label2, Me.Label3}

        For Each lbl As Label In lbls
            lbl.Text = lbl.Name
            lbl.Font = New System.Drawing.Font("MS UI Gothic", 18.0!, System.Drawing.FontStyle.Regular, _
                                                 System.Drawing.GraphicsUnit.Point, CType(128, Byte))
            lbl.BorderStyle = BorderStyle.FixedSingle
        Next
    End Sub

    ' LabelのMouseDownイベントを共通で行う。 
    Private Sub LabelMouseDown(ByVal sender As System.ObjectByVal e As System.Windows.Forms.MouseEventArgs) _
    Handles Label1.MouseDown, Label2.MouseDown, Label3.MouseDown
        ' 対象のラベル 
        Dim lbl As Label = DirectCast(sender, Label)
        Me.dictFlgMouseDowns(lbl) = True
        Me.dictMovedPoints(lbl) = e.Location
    End Sub

    Private Sub Label1_MouseUp(ByVal sender As System.ObjectByVal e As System.Windows.Forms.MouseEventArgs) _
    Handles Label1.MouseUp, Label2.MouseUp, Label3.MouseUp
        Dim lbl As Label = DirectCast(sender, Label)
        Me.dictFlgMouseDowns(lbl) = False
        'Console.WriteLine("MouseUp")  
    End Sub

    ' LabelのMouseMoveイベントを共通で行う。 
    Private Sub LabelMouseMove(ByVal sender As System.ObjectByVal e As System.Windows.Forms.MouseEventArgs) _
    Handles Label1.MouseMove, Label2.MouseMove, Label3.MouseMove
        ' 対象のラベル 
        Dim lbl As Label = DirectCast(sender, Label)

        If Not Me.dictFlgMouseDowns.ContainsKey(lbl) Then
            Return
        End If

        Dim flgMouseDown = Me.dictFlgMouseDowns(lbl)

        If Not flgMouseDown Then
            Return
        End If

        Dim labelPoint As Point = Me.dictMovedPoints(lbl)
        Dim p As Point = Me.Label1.Parent.PointToClient(Cursor.Position)
        lbl.Location = New Point(p.X - labelPoint.X, p.Y - labelPoint.Y)
        lbl.Text = lbl.Location.ToString()
    End Sub

End Class
投稿者 葉月  (社会人) 投稿日時 2012/2/11 13:28:18
http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=10651
で質問があったので、3点の重要な説明をします。
説明は、コントロールが複数のケースです。

①イベントプロシージャーの利用
LabelMouseDown、Label_1MouseUp、LabelMouseMoveにHandles句で
イベントの準備を行っています。
Handles Label1.MouseDown, Label2.MouseDown, Label3.MouseDown

Handles Label1.MouseUp, Label2.MouseUp, Label3.MouseUp

Handles Label1.MouseMove, Label2.MouseMove, Label3.MouseMove

上記3つのイベントに、動かしたいラベルを全部記述する必要があります。
(今回は3個ずつですが、10個なら各イベントに7個ずつ追加する必要
があります)
一例:
Private Sub LabelMouseDown(ByVal sender As System.ObjectByVal e As System.Windows.Forms.MouseEventArgs) _
Handles Label1.MouseDown, Label2.MouseDown, Label3.MouseDown, Label4.MouseDown,Label5.MouseDown, _
Label6.MouseDown, Label7.MouseDown, Label8.MouseDown, Label9.MouseDown, Label10.MouseDown



②イベントの引数にあるsenderオブジェクトを利用して複数のラベルを処理
' 対象のラベル 
Dim lbl As Label = DirectCast(sender, Label)


senderには、呼ばれたコントロール(Labelなど)の情報が入るので、
DirectCastで変換し代入すれば、呼ばれたコントロールの操作が
行えます。
こうすると複数のコントロールの対応が行えるようになります。
詳しくはデバッグでsenderの内容を見てください。


③Dictionaryクラスを使い、各ラベルと座標を結び付ける。
dictMovedPointsを■でわけると、以下の情報にわかれます。
キー   値
Label1■{X=122,Y=85}
Label2■{X=0,Y=5}
Label3■{X=60,Y=55}

コードを例に説明します。
Dim lbl As Label = DirectCast(sender, Label)
' 省略 
Dim labelPoint As Point = Me.dictMovedPoints(lbl)

lblがLabel2だったら、labelPointsに座標の{X=0,Y=5}が代入されます。
詳しくはデバッグして、dictMovedPointsを見てください。