マウス移動時の制御について(コントロール) への返答
投稿で使用できる特殊コードの説明。(別タブで開きます。)
以下の返答は逆順(新しい順)に並んでいます。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2016/10/12 11:47:40
案1 で作ってみました。
古いバージョン(VB.NET 2002 など)だと使えない機能も含まれていますが御容赦を。
Ctrl を押しながら左ドラッグを開始すればコピーになりますが、
(左ドラッグを始めてから Ctrl を押すのはNG)
ついでに、ドラッグ中に[Esc]が押されたらドラッグ処理をキャンセルさせています。
古いバージョン(VB.NET 2002 など)だと使えない機能も含まれていますが御容赦を。
Ctrl を押しながら左ドラッグを開始すればコピーになりますが、
(左ドラッグを始めてから Ctrl を押すのはNG)
ついでに、ドラッグ中に[Esc]が押されたらドラッグ処理をキャンセルさせています。
Public Class Form1
Private dragTarget As Control = Nothing
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
KeyPreview = True
'コントロールをドラッグ可能にする
AddHandler TextBox1.MouseDown, AddressOf Target_MouseDown
AddHandler Label1.MouseDown, AddressOf Target_MouseDown
AddHandler CheckBox1.MouseDown, AddressOf Target_MouseDown
End Sub
Private Sub Target_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
If e.Button <> System.Windows.Forms.MouseButtons.Left Then
Return
End If
'ドラッグされたコントロール自身
Dim this As Control = DirectCast(sender, Control)
'Ctrl が押されていたかどうか
Dim isCopy As Boolean = (Control.ModifierKeys And Keys.Control) = Keys.Control
'Ctrl が押されていなければ自身をセット
'押されてたらコントロールを複製してセット
If isCopy Then
'新しいコントロールを作成し、位置・サイズ・内容等を複製
dragTarget = DirectCast(Activator.CreateInstance(this.GetType()), Control)
dragTarget.Text = this.Text
dragTarget.Parent = this.Parent
dragTarget.SetBounds(this.Left, this.Top, this.Width, this.Height)
this.Capture = False
dragTarget.Visible = True
dragTarget.BringToFront()
dragTarget.Focus()
dragTarget.Capture = True
AddHandler dragTarget.MouseDown, AddressOf Target_MouseDown
Else
dragTarget = this
End If
Cursor = Cursors.Hand 'コピーと移動でカーソルを変えるのも良いかも
'現在の位置情報を Tag プロパティに保存しています
Dim oldPos As Point = dragTarget.Location
Dim dragOffset As Size = dragTarget.Parent.PointToClient(MousePosition) - oldPos
dragTarget.Tag = New Object() {dragOffset, oldPos, isCopy}
'イベントを動的に付与します
AddHandler dragTarget.MouseMove, AddressOf Target_MouseMove
AddHandler dragTarget.MouseUp, AddressOf Target_MouseUp
End Sub
Private Sub Target_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
If dragTarget Is Nothing Then
Return
End If
'Tag プロパティに保存していた位置情報を復元
Dim target As Control = DirectCast(sender, Control)
Dim pack() As Object = CType(target.Tag, Object())
Dim dragOffset As Size = CType(pack(0), Size)
Dim oldPos As Point = CType(pack(1), Point)
'現在の位置情報
Dim curPos As Point = target.Parent.PointToClient(MousePosition) - dragOffset
'縦横どちらに多く動かしたかを調べて、
'垂直移動と水平移動を切り替えています
Dim moveOffset As New Size(Math.Abs(curPos.X - oldPos.X), Math.Abs(curPos.Y - oldPos.Y))
If moveOffset.Width = moveOffset.Height Then
target.Location = oldPos
ElseIf moveOffset.Width < moveOffset.Height Then
target.Location = New Point(oldPos.X, curPos.Y)
ElseIf moveOffset.Width > moveOffset.Height Then
target.Location = New Point(curPos.X, oldPos.Y)
End If
End Sub
Private Sub Target_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs)
If dragTarget IsNot Nothing AndAlso e.Button = System.Windows.Forms.MouseButtons.Left Then
Dim target As Control = DirectCast(sender, Control)
EndDrag(target)
End If
End Sub
'ドラッグを完了させる
Private Sub EndDrag(ByVal target As Control)
RemoveHandler target.MouseUp, AddressOf Target_MouseUp
RemoveHandler target.MouseMove, AddressOf Target_MouseMove
Cursor = Cursors.Default
target.Tag = Nothing
dragTarget = Nothing
End Sub
Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
'Esc が押されたらドラッグをキャンセル
If dragTarget IsNot Nothing AndAlso e.KeyCode = Keys.Escape Then
Dim pack() As Object = CType(dragTarget.Tag, Object())
If CBool(pack(2)) Then
'コピー中のコントロールを破棄
Using dragTarget
dragTarget.Parent.Controls.Remove(dragTarget)
EndDrag(dragTarget)
End Using
Else
'移動中のコントロールの位置を戻す
dragTarget.Location = CType(pack(1), Point)
EndDrag(dragTarget)
End If
End If
End Sub
End Class
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2016/10/11 22:52:01
> テキストボックス等のコントロールを
テキストボックスに対するドラッグ操作は、本来ならば文字列選択のために使われるものですよね。
ドラッグ操作を組み込むなら、別のコントロールに仕掛けた方が良いと思いますよ。たとえば Label とか。
> TextBox1.Location = Point.op_Subtraction(Me.PointToClient(System.Windows.Forms.Cursor.Position), StartPositon)
VB.NET 2002/2003 をお使いでしょうか? VB2005 以降では、
op_Subtraction メソッドの代わりに - 演算子を使います。具体的にはこんな感じ。
> コントロールの開始位置から同じX方向か同じY方向にしか移動できないようにしたい。
Location プロパティではなく、Left プロパティや Top プロパティを使ってみてください。
ただし今のままのコードだと、フォームの端を超えて移動できてしまいますので、
算出した座標の値を調べて、必要以上に移動されないようにしておいた方が良いでしょう。
> Ctrlキーでのコピー処理をしたい。
Ctrl が押されているかどうかは、ModifierKeys プロパティで分かります。
どの時点でコピーするのかも、仕様として定めておいた方が良いかもしれませんね。
(案1) ドラッグを開始した時点でコピーを作り、
ドラッグ中はそのコピーを移動させる。
(案2) ドラッグが完了した時点でコピーを作り、
ドロップされた位置にそのコピーを配置する。
テキストボックスに対するドラッグ操作は、本来ならば文字列選択のために使われるものですよね。
ドラッグ操作を組み込むなら、別のコントロールに仕掛けた方が良いと思いますよ。たとえば Label とか。
> TextBox1.Location = Point.op_Subtraction(Me.PointToClient(System.Windows.Forms.Cursor.Position), StartPositon)
VB.NET 2002/2003 をお使いでしょうか? VB2005 以降では、
op_Subtraction メソッドの代わりに - 演算子を使います。具体的にはこんな感じ。
TextBox1.Location = Me.PointToClient(System.Windows.Forms.Cursor.Position) - StartPositon
> コントロールの開始位置から同じX方向か同じY方向にしか移動できないようにしたい。
Location プロパティではなく、Left プロパティや Top プロパティを使ってみてください。
'TextBox1.Location = Me.PointToClient(System.Windows.Forms.Cursor.Position) - StartPositon
'TextBox1.Left = (Me.PointToClient(System.Windows.Forms.Cursor.Position) - StartPositon).X
TextBox1.Top = (Me.PointToClient(System.Windows.Forms.Cursor.Position) - StartPositon).Y
ただし今のままのコードだと、フォームの端を超えて移動できてしまいますので、
算出した座標の値を調べて、必要以上に移動されないようにしておいた方が良いでしょう。
> Ctrlキーでのコピー処理をしたい。
Ctrl が押されているかどうかは、ModifierKeys プロパティで分かります。
どの時点でコピーするのかも、仕様として定めておいた方が良いかもしれませんね。
(案1) ドラッグを開始した時点でコピーを作り、
ドラッグ中はそのコピーを移動させる。
(案2) ドラッグが完了した時点でコピーを作り、
ドロップされた位置にそのコピーを配置する。
投稿者 やむちゃ  (社会人)
投稿日時
2016/10/11 20:45:13
以下のようなコードで
フォーム上に配置したテキストボックス等のコントロールを
マウスでドラッグアンドドロップ可能にしました。
これを、
①コントロールの開始位置から同じX方向か同じY方向にしか移動できないようにしたい。
(将棋の飛車のような動き)
②①のような動きで、Ctrlキーでのコピー処理をしたい。
のように改造したいのですが、行き詰っています。
どのようにすればよいか、アドバイスをお願いいたします。
Public Class Form1
Private StartPositon As Size
Private Sub TextBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseDown
If e.Button = System.Windows.Forms.MouseButtons.Left Then
StartPositon = New Size(e.X, e.Y)
End If
End Sub
Private Sub TextBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseMove
If e.Button = System.Windows.Forms.MouseButtons.Left Then
TextBox1.Location = Point.op_Subtraction(Me.PointToClient(System.Windows.Forms.Cursor.Position), StartPositon)
End If
End Sub
End Class
フォーム上に配置したテキストボックス等のコントロールを
マウスでドラッグアンドドロップ可能にしました。
これを、
①コントロールの開始位置から同じX方向か同じY方向にしか移動できないようにしたい。
(将棋の飛車のような動き)
②①のような動きで、Ctrlキーでのコピー処理をしたい。
のように改造したいのですが、行き詰っています。
どのようにすればよいか、アドバイスをお願いいたします。
Public Class Form1
Private StartPositon As Size
Private Sub TextBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseDown
If e.Button = System.Windows.Forms.MouseButtons.Left Then
StartPositon = New Size(e.X, e.Y)
End If
End Sub
Private Sub TextBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseMove
If e.Button = System.Windows.Forms.MouseButtons.Left Then
TextBox1.Location = Point.op_Subtraction(Me.PointToClient(System.Windows.Forms.Cursor.Position), StartPositon)
End If
End Sub
End Class
早々にご回答頂き、しかもサンプルコードまでありがとうございます。
こんなコードが短時間で書けるなんて、凄いの一言です。
素晴らしいご回答により、本件はクローズと致します。