作成予定のボタンの動作で、MouseDownなどができないか
投稿者 るきお  (社会人)
投稿日時
2020/3/30 21:22:13
そこまでできているのなら、Clickと同じようにMouseDownとMouseUpもできますよ。
直ぐに試せるサンプル付きだったので、簡単に回答できました。
Imports System.Windows.Forms
Imports Microsoft.Win32
Imports System.Drawing
Imports System.Drawing.Imaging
Public Class Form1
Private testButtons() As System.Windows.Forms.Button
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'ボタンコントロール配列の作成(ここでは5つ作成)
Me.testButtons = New System.Windows.Forms.Button(4) {}
'ボタンコントロールのインスタンス作成し、プロパティを設定する
Me.SuspendLayout()
Dim i As Integer
For i = 0 To Me.testButtons.Length - 1
'インスタンス作成
Me.testButtons(i) = New System.Windows.Forms.Button
'プロパティ設定
Me.testButtons(i).Name = "Button" + i.ToString()
Me.testButtons(i).Text = i.ToString()
Me.testButtons(i).Size = New Size(30, 30)
Me.testButtons(i).Location = New Point(i * 30, 10)
'イベントハンドラに関連付け
AddHandler Me.testButtons(i).Click, AddressOf Me.testButtons_Click
AddHandler Me.testButtons(i).MouseDown, AddressOf Me.testButtons_MouseDown
AddHandler Me.testButtons(i).MouseUp, AddressOf Me.testButtons_MouseUp
Next i
'フォームにコントロールを追加
Me.Controls.AddRange(Me.testButtons)
Me.ResumeLayout(False)
End Sub
Private Sub testButtons_Click(ByVal sender As Object,
ByVal e As EventArgs)
'クリックされたボタンのNameを表示する
MessageBox.Show(CType(sender, System.Windows.Forms.Button).Name)
End Sub
Private Sub testButtons_MouseDown(sender As Object, e As MouseEventArgs)
DirectCast(sender, Button).BackColor = Color.Red
End Sub
Private Sub testButtons_MouseUp(sender As Object, e As MouseEventArgs)
DirectCast(sender, Button).BackColor = Color.Blue
End Sub
End Class
直ぐに試せるサンプル付きだったので、簡単に回答できました。
投稿者 (削除されました)  ()
投稿日時
2020/3/30 22:10:20
(削除されました)
投稿者 kojiro  (社会人)
投稿日時
2020/3/30 22:21:01
えーと、うごきますね。
ここで、ボタン1をマウスダウンしたとき、ボタン1が赤く染まり、そこから、ボタン2の場所で、マウスアップしたときには、ボタン1の色が青くないrます。これをボタン2を青くしたいのですが・・できるでしょうかw
ここで、ボタン1をマウスダウンしたとき、ボタン1が赤く染まり、そこから、ボタン2の場所で、マウスアップしたときには、ボタン1の色が青くないrます。これをボタン2を青くしたいのですが・・できるでしょうかw
投稿者 るきお  (社会人)
投稿日時
2020/3/31 08:44:37
それでは、testButtons_MouseUp をたとえば次のように修正するとよいと思います。
MouseUpイベントはそのときのマウスの位置とは関係がなく、MouseDownイベントを発生させたボタンと同じボタンで発生します。
MouseUpイベントでのsenderはMouseDownイベントでのsenderと同じコントロールを指します。
一方、今回 kojiro さんは、そうではなく、マウスアップした瞬間にマウスの下にあったボタンの色を青くしたいということなので、senderではなく、マウスの座標をもとにその座標にあるコントロールを取得する必要があります。これにはGetChildAdPointメソッドを使用します。
イベントの引数(e.Location)が表す座標は、イベントを発生させたボタンの左上が(0,0)という座標系ですので、フォームの座標系に変換するためにそのボタンの座標をたし算をしています。
この構造にすると、コントロールがどのような階層構造で配置されているかが重要になります。この例ではフォームに直接配置されているのでフォームのGetChildAtPointメソッドを使っていますが、PanelやPictureBoxなどフォームでないものに配置しているのであれば、変える必要がありますし、汎用で作るのは少し面倒になります。
Private Sub testButtons_MouseUp(sender As Object, e As MouseEventArgs)
'イベントを発生させたボタンを取得します。
'これはこの瞬間のマウスの座標とは関係なくMouseDownを発生させたボタンを同じです。
Dim eventSourceControl As Button = DirectCast(sender, Button)
'この瞬間のマウスの位置の下にあるコントロールを取得します。
Dim xInParent As Integer = e.Location.X + eventSourceControl.Location.X
Dim yInParent As Integer = e.Location.Y + eventSourceControl.Location.Y
Dim locationInParent As New Point(xInParent, yInParent)
Dim controlMouseOn As Control = Me.GetChildAtPoint(locationInParent)
'マウスの下に何かコントロールがあるのであれば、それの背景色を変更します。
If controlMouseOn IsNot Nothing Then
controlMouseOn.BackColor = Color.Blue
End If
End Sub
MouseUpイベントはそのときのマウスの位置とは関係がなく、MouseDownイベントを発生させたボタンと同じボタンで発生します。
MouseUpイベントでのsenderはMouseDownイベントでのsenderと同じコントロールを指します。
一方、今回 kojiro さんは、そうではなく、マウスアップした瞬間にマウスの下にあったボタンの色を青くしたいということなので、senderではなく、マウスの座標をもとにその座標にあるコントロールを取得する必要があります。これにはGetChildAdPointメソッドを使用します。
イベントの引数(e.Location)が表す座標は、イベントを発生させたボタンの左上が(0,0)という座標系ですので、フォームの座標系に変換するためにそのボタンの座標をたし算をしています。
この構造にすると、コントロールがどのような階層構造で配置されているかが重要になります。この例ではフォームに直接配置されているのでフォームのGetChildAtPointメソッドを使っていますが、PanelやPictureBoxなどフォームでないものに配置しているのであれば、変える必要がありますし、汎用で作るのは少し面倒になります。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2020/3/31 11:30:37
> 変える必要がありますし、汎用で作るのは少し面倒になります。
Cursor.Position を使えば、現在のカーソル位置をスクリーン座標で得ることができます。
> Dim eventSourceControl As Button = DirectCast(sender, Button)
親コントロールは Parent プロパティ、親フォームは FindForm メソッドで得られるので、
それぞれのクライアント座標に変換するために、こういう方法が使えるかもしれません。
> MouseUpイベントはそのときのマウスの位置とは関係がなく、MouseDownイベントを発生させたボタンと同じボタンで発生します。
たとえば Label を MouseDown した後、Button の上で MouseUp したとしても、
Button の MouseUp イベントは発生しません。
(ドラッグ処理を実装するような場合は、むしろその方が扱いやすい)
しかし、どこで MouseDown されたとしても、常に MouseUp した場所の座標を
捕らえたいような場合には、かわりに RawInput を使うこともできます。
https://www.nuget.org/packages/SharpDX.RawInput/
Cursor.Position を使えば、現在のカーソル位置をスクリーン座標で得ることができます。
> Dim eventSourceControl As Button = DirectCast(sender, Button)
親コントロールは Parent プロパティ、親フォームは FindForm メソッドで得られるので、
それぞれのクライアント座標に変換するために、こういう方法が使えるかもしれません。
Dim posScreen = Cursor.Position
Dim posSelf = eventSourceControl.PointToClient(posScreen)
Dim posContainer = eventSourceControl.Parent.PointToClient(posScreen)
Dim posForm = eventSourceControl.FindForm().PointToClient(posScreen)
> MouseUpイベントはそのときのマウスの位置とは関係がなく、MouseDownイベントを発生させたボタンと同じボタンで発生します。
たとえば Label を MouseDown した後、Button の上で MouseUp したとしても、
Button の MouseUp イベントは発生しません。
(ドラッグ処理を実装するような場合は、むしろその方が扱いやすい)
しかし、どこで MouseDown されたとしても、常に MouseUp した場所の座標を
捕らえたいような場合には、かわりに RawInput を使うこともできます。
https://www.nuget.org/packages/SharpDX.RawInput/
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
SharpDX.RawInput.Device.RegisterDevice(
SharpDX.Multimedia.UsagePage.Generic,
SharpDX.Multimedia.UsageId.GenericMouse,
SharpDX.RawInput.DeviceFlags.None)
AddHandler SharpDX.RawInput.Device.MouseInput, AddressOf RawInput_MouseInput
End Sub
Private Sub RawInput_MouseInput(sender As Object, e As SharpDX.RawInput.MouseInputEventArgs)
Dim isMouseDown = e.ButtonFlags.HasFlag(SharpDX.RawInput.MouseButtonFlags.LeftButtonDown)
Dim isMouseUp = e.ButtonFlags.HasFlag(SharpDX.RawInput.MouseButtonFlags.LeftButtonUp)
'左マウスボタンが操作されていないので、何もしない
If Not (isMouseDown OrElse isMouseUp) Then Return
'現在のマウス位置のコントロールを調べる
Dim child = HitTest(Me, MousePosition)
'それが Button でない場合は何もしない
If TypeOf child IsNot Button Then Return
'MouseDown 箇所のボタンを赤く染める
If isMouseDown Then child.BackColor = Color.Red
'MouseUp 箇所のボタンを青く染める
If isMouseUp Then child.BackColor = Color.Blue
End Sub
Private Shared Function HitTest(root As Control, screenPos As Point) As Control
Dim current = root
Dim last As Control = Nothing
Do Until current Is Nothing
last = current
current = current.GetChildAtPoint(current.PointToClient(screenPos))
Loop
Return last
End Function
End Class
投稿者 kojiro  (社会人)
投稿日時
2020/3/31 14:39:47
るきおさんの回答で、完全に動作しました。驚きました。魔界さんのおっしゃる点は、確認しておりませんん。ごめんなさい。以下のように、tabを作成し、その中にボタンを配置して、同様に記述してみました。
Imports System.Windows.Forms
Imports Microsoft.Win32
Imports System.Drawing
Imports System.Drawing.Imaging
Public Class Form1
Dim button As System.Windows.Forms.Button
Dim btnar As New List(Of Button)
Dim tb As New System.Windows.Forms.TabControl
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim tb As New System.Windows.Forms.TabControl
Dim i As Integer
With tb
.Name = "TabControl1"
.Left = 20 '470
.Top = 20
.Width = 250
.Height = 220
.Visible = True
End With
Controls.Add(tb)
For i = 0 To 2
Dim tab As New TabPage
tab.UseVisualStyleBackColor = True '色が白くなります
tab.Text = CStr(i) ' Cell_x2) '"tab" & CStr(i + 1) 'TabPageの表題です
tab.Name = "tabpage" & CStr(i + 1) 'TabPageに名前を付けます
'tb.Add(tab) 'TabPageをリストにします
Me.Controls("TabControl1").Controls.Add(tab) 'TabPageをコントロールにAddします
Next
Dim str_c As String
For i = 0 To 2
Dim tab_name As String = "tabpage" & CStr(i + 1)
For k = 1 To 3 '************* 7
'------------------------------------------------------
button = New System.Windows.Forms.Button()
str_c = CStr(i) & CStr(k)
button.Name = str_c
button.Text = str_c
button.Location = New Point(20 + 70 * (k - 1), 50)
button.Size = New System.Drawing.Size(70, 20)
btnar.Add(button)
tb.Controls(tab_name).Controls.Add(button)
AddHandler button.Click, AddressOf Me.Button_Click 'system_SessionEnding 'EventHandler
AddHandler button.MouseUp, AddressOf Button_MouseUp 'system_SessionEnding 'EventHandler
AddHandler button.MouseDown, AddressOf Button_MouseDown 'system_SessionEnding 'EventHandler
Next
Next
End Sub
Private Sub Button_Click(sender As Object, e As EventArgs)
'クリックされたボタンのNameを表示する
MessageBox.Show(CType(sender, System.Windows.Forms.Button).Name)
End Sub
Private Sub Button_MouseUp(sender As Object, e As MouseEventArgs)
'イベントを発生させたボタンを取得します。
'これはこの瞬間のマウスの座標とは関係なくMouseDownを発生させたボタンを同じです。
Dim eventSourceControl As Button = DirectCast(sender, Button)
'この瞬間のマウスの位置の下にあるコントロールを取得します。
Dim xInParent As Integer = e.Location.X + eventSourceControl.Location.X
Dim yInParent As Integer = e.Location.Y + eventSourceControl.Location.Y
Dim locationInParent As New Point(xInParent, yInParent)
Dim controlMouseOn As Control = Me.GetChildAtPoint(locationInParent)
'マウスの下に何かコントロールがあるのであれば、それの背景色を変更します。
If controlMouseOn IsNot Nothing Then
controlMouseOn.BackColor = Color.Blue
End If
End Sub
Private Sub Button_MouseDown(sender As Object, e As MouseEventArgs)
DirectCast(sender, Button).BackColor = Color.Red
End Sub
End Class
MouseDownで赤くはなるのですが、MouseUpで青くはなりません。おっしゃるように、 Me.GetChildAtPoint(locationInParent)が動いていないのかもしれません。
Imports System.Windows.Forms
Imports Microsoft.Win32
Imports System.Drawing
Imports System.Drawing.Imaging
Public Class Form1
Dim button As System.Windows.Forms.Button
Dim btnar As New List(Of Button)
Dim tb As New System.Windows.Forms.TabControl
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim tb As New System.Windows.Forms.TabControl
Dim i As Integer
With tb
.Name = "TabControl1"
.Left = 20 '470
.Top = 20
.Width = 250
.Height = 220
.Visible = True
End With
Controls.Add(tb)
For i = 0 To 2
Dim tab As New TabPage
tab.UseVisualStyleBackColor = True '色が白くなります
tab.Text = CStr(i) ' Cell_x2) '"tab" & CStr(i + 1) 'TabPageの表題です
tab.Name = "tabpage" & CStr(i + 1) 'TabPageに名前を付けます
'tb.Add(tab) 'TabPageをリストにします
Me.Controls("TabControl1").Controls.Add(tab) 'TabPageをコントロールにAddします
Next
Dim str_c As String
For i = 0 To 2
Dim tab_name As String = "tabpage" & CStr(i + 1)
For k = 1 To 3 '************* 7
'------------------------------------------------------
button = New System.Windows.Forms.Button()
str_c = CStr(i) & CStr(k)
button.Name = str_c
button.Text = str_c
button.Location = New Point(20 + 70 * (k - 1), 50)
button.Size = New System.Drawing.Size(70, 20)
btnar.Add(button)
tb.Controls(tab_name).Controls.Add(button)
AddHandler button.Click, AddressOf Me.Button_Click 'system_SessionEnding 'EventHandler
AddHandler button.MouseUp, AddressOf Button_MouseUp 'system_SessionEnding 'EventHandler
AddHandler button.MouseDown, AddressOf Button_MouseDown 'system_SessionEnding 'EventHandler
Next
Next
End Sub
Private Sub Button_Click(sender As Object, e As EventArgs)
'クリックされたボタンのNameを表示する
MessageBox.Show(CType(sender, System.Windows.Forms.Button).Name)
End Sub
Private Sub Button_MouseUp(sender As Object, e As MouseEventArgs)
'イベントを発生させたボタンを取得します。
'これはこの瞬間のマウスの座標とは関係なくMouseDownを発生させたボタンを同じです。
Dim eventSourceControl As Button = DirectCast(sender, Button)
'この瞬間のマウスの位置の下にあるコントロールを取得します。
Dim xInParent As Integer = e.Location.X + eventSourceControl.Location.X
Dim yInParent As Integer = e.Location.Y + eventSourceControl.Location.Y
Dim locationInParent As New Point(xInParent, yInParent)
Dim controlMouseOn As Control = Me.GetChildAtPoint(locationInParent)
'マウスの下に何かコントロールがあるのであれば、それの背景色を変更します。
If controlMouseOn IsNot Nothing Then
controlMouseOn.BackColor = Color.Blue
End If
End Sub
Private Sub Button_MouseDown(sender As Object, e As MouseEventArgs)
DirectCast(sender, Button).BackColor = Color.Red
End Sub
End Class
MouseDownで赤くはなるのですが、MouseUpで青くはなりません。おっしゃるように、 Me.GetChildAtPoint(locationInParent)が動いていないのかもしれません。
投稿者 (削除されました)  ()
投稿日時
2020/4/1 14:53:34
(削除されました)
投稿者 kojiro  (社会人)
投稿日時
2020/4/1 15:33:28
上記のコードで、
MsgBox(e.Location.X)
MsgBox(e.Location.Y)
MsgBox(eventSourceControl.Location.X)
MsgBox(eventSourceControl.Location.Y)
で、同じボタンでUpしても
e.Location.X=35
e.Location.Y=8
eventSourceControl.Location.X=20
eventSourceControl.Location.Y=50
で、おかしいですね。20、50は、最初に作られたButtonの位置になります。
buttonが配列になっていないからか・・
tabはあきらめようと思います。るきおさん・・大変ありがとうございます。ボタンに登録したデータを右クリックのドロップダウンのような動作で、移動できるのかな、と思っています。
魔界さんのおっしゃるSharpDX.RawInputを、.NETに追加する方法を、今後の参考に、教えて頂けたら、幸いです。
MsgBox(e.Location.X)
MsgBox(e.Location.Y)
MsgBox(eventSourceControl.Location.X)
MsgBox(eventSourceControl.Location.Y)
で、同じボタンでUpしても
e.Location.X=35
e.Location.Y=8
eventSourceControl.Location.X=20
eventSourceControl.Location.Y=50
で、おかしいですね。20、50は、最初に作られたButtonの位置になります。
buttonが配列になっていないからか・・
tabはあきらめようと思います。るきおさん・・大変ありがとうございます。ボタンに登録したデータを右クリックのドロップダウンのような動作で、移動できるのかな、と思っています。
魔界さんのおっしゃるSharpDX.RawInputを、.NETに追加する方法を、今後の参考に、教えて頂けたら、幸いです。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2020/4/1 15:57:09
マウス・キーボード・フォーカス遷移系のイベントデータを確認する際に、MsgBox を使用することは避けてください。
イベントの流れが阻害されてしまうため、連続して実行した場合とで、動作が変わってしまうことがあります。
代わりに、Debug.WriteLine を使うなどして確認頂くことをお奨めします。
> 20、50は、最初に作られたButtonの位置になります。
るきおさんの説明にもありましたが、MouseUpイベントはそのときのマウスの位置とは関係がなく、
MouseDown イベントを発生させたボタンと同じボタンで発生するからです。
つまり、MouseUp イベントの sender は、現在のマウス座標に関係なく、
MouseDown が発生した時の sender と同じである、ということです。
上記を試すと、マウスボタンを離した時の座標がどこにあったとしても、
Capture が True になるのは、MouseDown された時のボタンであることが分かるかと思います。
> SharpDX.RawInputを、.NETに追加する方法を、今後の参考に、教えて頂けたら、幸いです。
お使いの Visual Studio のバージョンにもよりますが、よほど古い物でなければ、
[ツール]-[NuGet パッケージ マネージャー] というメニュー項目があると思います。
そこから NuGet パッケージの管理画面を起動し、
パッケージ ソースに "nuget.org" を選択した上で、
「参照」タブに切り替えて検索ボックスに「SharpDX.RawInput」と入力して、
プロジェクトにインストールしてみてください。
イベントの流れが阻害されてしまうため、連続して実行した場合とで、動作が変わってしまうことがあります。
代わりに、Debug.WriteLine を使うなどして確認頂くことをお奨めします。
> 20、50は、最初に作られたButtonの位置になります。
るきおさんの説明にもありましたが、MouseUpイベントはそのときのマウスの位置とは関係がなく、
MouseDown イベントを発生させたボタンと同じボタンで発生するからです。
つまり、MouseUp イベントの sender は、現在のマウス座標に関係なく、
MouseDown が発生した時の sender と同じである、ということです。
Private Sub Buttons_MouseUp(sender As Object, e As MouseEventArgs) Handles Button1.MouseUp, Button2.MouseUp, Button3.MouseUp
Label1.Text = CStr(Button1.Capture)
Label2.Text = CStr(Button2.Capture)
Label3.Text = CStr(Button3.Capture)
End Sub
上記を試すと、マウスボタンを離した時の座標がどこにあったとしても、
Capture が True になるのは、MouseDown された時のボタンであることが分かるかと思います。
> SharpDX.RawInputを、.NETに追加する方法を、今後の参考に、教えて頂けたら、幸いです。
お使いの Visual Studio のバージョンにもよりますが、よほど古い物でなければ、
[ツール]-[NuGet パッケージ マネージャー] というメニュー項目があると思います。
そこから NuGet パッケージの管理画面を起動し、
パッケージ ソースに "nuget.org" を選択した上で、
「参照」タブに切り替えて検索ボックスに「SharpDX.RawInput」と入力して、
プロジェクトにインストールしてみてください。
今回は無理かもしれません。以下
Imports System.Windows.Forms
Imports Microsoft.Win32
Imports System.Drawing
Imports System.Drawing.Imaging
Public Class Form1
Private testButtons() As System.Windows.Forms.Button
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'ボタンコントロール配列の作成(ここでは5つ作成)
Me.testButtons = New System.Windows.Forms.Button(4) {}
'ボタンコントロールのインスタンス作成し、プロパティを設定する
Me.SuspendLayout()
Dim i As Integer
For i = 0 To Me.testButtons.Length - 1
'インスタンス作成
Me.testButtons(i) = New System.Windows.Forms.Button
'プロパティ設定
Me.testButtons(i).Name = "Button" + i.ToString()
Me.testButtons(i).Text = i.ToString()
Me.testButtons(i).Size = New Size(30, 30)
Me.testButtons(i).Location = New Point(i * 30, 10)
'イベントハンドラに関連付け
AddHandler Me.testButtons(i).Click, AddressOf Me.testButtons_Click
Next i
'フォームにコントロールを追加
Me.Controls.AddRange(Me.testButtons)
Me.ResumeLayout(False)
End Sub
Private Sub testButtons_Click(ByVal sender As Object, _
ByVal e As EventArgs)
'クリックされたボタンのNameを表示する
MessageBox.Show(CType(sender, System.Windows.Forms.Button).Name)
End Sub
End Class
などで、クリック時の動作は、できますが、この作成するボタンのMouseDownやMouseUpの動作を、定義できますでしょうか?