午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

マウスドラッグでコントロールの移動とサイズ変更LabelとPictureBox

Pixtack紫陽花の方がうまくいかないからちょっと別のテスト

イメージ 5
基本
ラベルとPictureBoxをマウスドラッグで移動
 
イメージ 6
Labelをマウスドラッグで動かしてPictureBoxのサイズと位置を変化させている
よくある動きだけど、今回はじめてできた!
 
Pixtack紫陽花やPixtrimの時にも挑戦したけど
範囲選択でできたのは右下の点だけでの動きだけだった
今回は8個のすべての点で期待通りに動いている
今までうまく動かなかった原因の一つが
サイズ変更にマウスドラッグしているものを中心に考えていたから
 
今回でもそうだけどマウスドラッグしているのは
Labelコントロール(Labelオブジェクト?)
これの位置を判定してそこからPictureBoxのサイズと位置を変更しようとしていた
 
今回はマウスの移動距離を中心にして考えたっていうか計算した
移動距離と移動方向からPictureBoxのサイズと位置を設定して
それからLabelの位置を設定
つまりLabelはマウスで直接動かしている様に見えているけど本当は間接的に動かしている
 
基本から
マウスドラッグでコントロールの移動

f:id:gogowaten:20191016130317p:plain

最低限必要なイベントはMouseDownとMouseMoveのふたつ
 
 
Private Click_初期クリック位置 As Point

Private Sub Label1_MouseDown(sender As Object, e As MouseEventArgs) Handles Label1.MouseDown
    If e.Button = Windows.Forms.MouseButtons.Left Then
        Click_初期クリック位置 = e.Location

    End If
End Sub

Private Sub Label1_MouseMove(sender As Object, e As MouseEventArgs) Handles Label1.MouseMove
    If e.Button = Windows.Forms.MouseButtons.Left Then
        Dim mp移動先座標 As New Point(
            e.X - Click_初期クリック位置.X + sender.location.x,
            e.Y - Click_初期クリック位置.Y + sender.location.y)
        sender.location = mp移動先座標 'ラベルの移動

    End If
End Sub

f:id:gogowaten:20191016130427p:plain

画像だとこう、たったこれだけ
移動させるならこれだけ
 
 
内容とは関係無けどコードの途中で改行させたいとき、半角スペースとアンダーバーを使わなくてもできる場合があることを今日知ったのは↓から
2010の頃からあったのね
今までも特に不便だと思っていなかったんだけど使ってみたらたしかに見やすくなる
 
内容に戻って、
Label1をマウスでクリックしたっていうMouseDownイベントで
クリックした位置はe.Locationでわかる、このクリックした位置ってのはLabel1の中の位置なのでLabel1のギリギリ左上をクリックした場合は(1,1)とかになる、
でそれを「Click_初期クリック位置」に記憶
Click_初期クリック位置 = e.Location
 
次はマウスを動かしたイベントのMouseMove
これもe.Locationで動いたマウスカーソルの位置がわかる
e.Xならx座標、e.Yはy座標がわかる
 
あとは引き算で
e.X - Click_初期クリック位置.X
e.Y - Click_初期クリック位置.Y
これでそれぞれマウスのx,yの移動距離がわかる
 
次はこの移動距離をLabel1のx,yにそれぞれ足し算すればいいだけ
e.X - Click_初期クリック位置.X + sender.location.x
e.Y - Click_初期クリック位置.Y + sender.location.y
senderはMouseMoveイベントの主、なので今回はLabel1になる
これでLabel1の移動先の位置が判明
 
マウスドラッグしているものしか動かさないないならこれでいいんだけど
連動していろいろ動かしたりサイズを変えたりする時は後回しにして
うまくいったのが今回
重要なのは動かしているものよりもマウスの移動距離だった
 
PictureBoxのサイズをマウスドラッグで変更
マウスの移動に対してPictureBoxをどう動かしたら辻褄が合うのか

f:id:gogowaten:20191016130613p:plain

またエクセル方眼紙wエクセル方眼紙便利すぎる
「逆」ってあるのが+と-を入れ替えるってこと
「順」はそのままつかうってことで
「0」は必ず0をしていするってこと
 
PictureBoxやその他のコントロール全部の座標の基準は左上になっているので
左と上方向にサイズを変更する時は位置も変更しないとおかしな動きになる
ボタン(Label)で言うとR、RD、D以外の5つのボタンを使って左と上方向にサイズ変更する時は移動が必要
マウスの移動距離と動かしているLabelの組み合わせでPictureBoxのサイズと位置を設定してから
PictureBoxのサイズと位置を元にLabelの位置を決定
今回のはスッキリかけたと思う(自画自賛)
Pixtrimの時でもできなくて諦めて妥協した感じになっているから直したいけど
直せるかなあ
↓スッキリかけたと思い込んでいい気分になっている全文
 
Public Class Form1
    Private Click_初期クリック位置 As Point
    Private mp移動距離 As Point
    Private list_Label As New Generic.List(Of Label) 'ポイントラベルのリスト
    Private lbl動かしているラベル As Label
   Private Sub Label1_MouseDown(sender As Object, e As MouseEventArgs) Handles Label1.MouseDown, PictureBox1.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left Then
            Click_初期クリック位置 = e.Location

        End If
    End Sub
    Private Sub Label1_MouseMove(sender As Object, e As MouseEventArgs) Handles Label1.MouseMove, PictureBox1.MouseMove
        If e.Button = Windows.Forms.MouseButtons.Left Then

            Dim mp移動先座標 As New Point(
                e.X - Click_初期クリック位置.X + sender.location.x,
                e.Y - Click_初期クリック位置.Y + sender.location.y)
            sender.location = mp移動先座標 'ラベルの移動

        End If

    End Sub
    Private Sub MouseDownマウスクリック初期位置(sender As Object, e As MouseEventArgs)
        Click_初期クリック位置 = e.Location
        lbl動かしているラベル = sender
    End Sub
    Private Sub MouseMoveマウスドラッグでPictureBoxサイズと位置を変更(sender As Object, e As MouseEventArgs)
        If e.Button = Windows.Forms.MouseButtons.Left Then
            mp移動距離 = New Point(
                e.X - Click_初期クリック位置.X,
                e.Y - Click_初期クリック位置.Y)

            Call PictureBoxの大きさ変更(sender) 'マウスの移動距離を使って求める

            'ラベルの移動は画像の位置やサイズから求めるので画像を先に処理した方がいい
            'マウスで動かしているラベルの位置も気にすることなかった
            '上下左右のラベルは斜めには動かないようにする処理は必要なかった
            '動かしていない7つのラベルの位置だけでなく8つすべてのラベルの位置調整
            'サイズと位置を調整した画像を元に位置を決めるだけでよかった…
            Dim ps = ラベルの位置配列(Me.PictureBox1)
            Dim lName() As String = {"LU", "LD", "RU", "RD", "U", "D", "L", "R"} 'ラベルの名前
            For i As Integer = 0 To UBound(lName)
                
                Me.Controls(lName(i)).Location = ps(i)
                
            Next

        End If
    End Sub
    Private Sub ラベル表示()
        Call ラベル非表示() '一旦リセット

        ''各ラベルの初期座標の配列作成
        Dim ps = ラベルの位置配列(Me.PictureBox1)

        Dim lSize As Integer = 10 'ラベルの大きさ
        Dim lName() As String = {"LU", "LD", "RU", "RD", "U", "D", "L", "R"} 'ラベルの名前

        For i As Integer = 0 To UBound(ps)
            Dim L As New Label
            'Dim nps As New Point(-5, 5)
            'ps(i).Offset(nps)'オフセット

            With L
                .Location = ps(i)
                .Name = lName(i)
                .Width = lSize
                .Height = lSize
                .BackColor = Color.LimeGreen
                .Cursor = Cursors.Hand 'マウスカーソルの形
                '.BringToFront() 'ここで最前面に表示を指定しても無意味なので表示した後に指定
            End With

            Me.Controls.Add(L) 'フォームに表示(追加)
            L.BringToFront() '最前面に表示
            list_Label.Add(L) 'リストに追加

            'イベント
            AddHandler L.MouseDown, AddressOf MouseDownマウスクリック初期位置
            AddHandler L.MouseMove, AddressOf MouseMoveマウスドラッグでPictureBoxサイズと位置を変更

        Next
        Me.Controls("RD").BringToFront() '右下のラベルを一番上にする

    End Sub
    Private Sub ラベル非表示()
        If list_Label.Count = 0 Then Exit Sub

        For i As Integer = 0 To list_Label.Count - 1
            Me.Controls.Remove(list_Label.Item(i))
            list_Label.Item(i).Dispose()

        Next

        list_Label.Clear()
    End Sub
    Private Sub PictureBoxの大きさ変更(L As Label)
        'ラベルが動いたら、ラベルの位置に合うように大きさを変更すればいい?
        '→ラベルの位置よりマウスの移動距離で計算した
        'マウスの移動距離を入れる変数を外に出して皆で共有→mp移動距離
        'SizeはPointでも指定できる
        '移動しているラベルの名前から処理を選択
        '上下左右、左上、右上、右下、左下でそれぞれ処理をわけた



        Dim x移動距離 As Integer = mp移動距離.X
        Dim y移動距離 As Integer = mp移動距離.Y
        Dim soサイズ加算値 As New Point(0, 0)
        Dim ps画像サイズ As New Point(Me.PictureBox1.Size)
        Dim mo画像移動加算値 As New Point(0, 0)
        Dim pp画像位置 As New Point(Me.PictureBox1.Location) 'フォーム上の画像の位置

        Select Case L.Name
            Case "U"
                soサイズ加算値 = New Point(0, -y移動距離)
                mo画像移動加算値 = New Point(0, y移動距離)
            Case "D"
                soサイズ加算値 = New Point(0, y移動距離)
                mo画像移動加算値 = New Point(0, 0)
            Case "L"
                soサイズ加算値 = New Point(-x移動距離, 0)
                mo画像移動加算値 = New Point(x移動距離, 0)
            Case "R"
                soサイズ加算値 = New Point(x移動距離, 0)
                mo画像移動加算値 = New Point(0, 0)
            Case "LU"
                soサイズ加算値 = New Point(-x移動距離, -y移動距離)
                mo画像移動加算値 = New Point(x移動距離, y移動距離)
            Case "RU"
                soサイズ加算値 = New Point(x移動距離, -y移動距離)
                mo画像移動加算値 = New Point(0, y移動距離)
            Case "RD"
                soサイズ加算値 = New Point(x移動距離, y移動距離)
                mo画像移動加算値 = New Point(0, 0)
            Case "LD"
                soサイズ加算値 = New Point(-x移動距離, y移動距離)
                mo画像移動加算値 = New Point(x移動距離, 0)
        End Select

        '画像の大きさを1x1以下にはしないように
        If ps画像サイズ.X + soサイズ加算値.X < 1 Or ps画像サイズ.Y + soサイズ加算値.Y < 1 Then
            soサイズ加算値 = New Point(0, 0)
            mo画像移動加算値 = New Point(0, 0)
        End If

        '画像のサイズと位置をセット
        ps画像サイズ.Offset(soサイズ加算値)
        pp画像位置.Offset(mo画像移動加算値)
        Me.PictureBox1.Size = ps画像サイズ
        Me.PictureBox1.Location = pp画像位置
      
    End Sub
    Private Function ラベルの位置配列(pb As PictureBox) As Point()
        Dim picL As Integer = pb.Left
        Dim picT As Integer = pb.Top
        Dim picW As Integer = pb.Width
        Dim picH As Integer = pb.Height

        '各ラベルの初期座標の配列作成
        Dim pLU As New Point(Me.PictureBox1.Location)
        Dim pLD As New Point(picL, picT + picH)
        Dim pRU As New Point(picL + picW, picT)
        Dim pRD As New Point(picL + picW, picT + picH)
        Dim pU As New Point(picL + (picW / 2), picT)
        Dim pD As New Point(picL + (picW / 2), picT + picH)
        Dim pL As New Point(picL, picT + (picH / 2))
        Dim pR As New Point(picL + picW, picT + (picH / 2))
        Dim ps() As Point = {pLU, pLD, pRU, pRD, pU, pD, pL, pR}
        Return ps

    End Function
End Class
こうしてみると長いな
 
画像だとこう、画像の大きさ1025x5148

f:id:gogowaten:20191016130848p:plain

画像の大きさ1025x5148
実行ファイルとソースダウンロード先1
マウスドラッグでコントロールの移動.zip
 
 関連記事
今回のを利用して改善
 
8年後