回答編集履歴
5
WM_NCMOUSEMOVEの処理が正しくなかったのを修正
answer
CHANGED
@@ -114,11 +114,18 @@
|
|
114
114
|
if (m.Msg == WM_MOUSEMOVE || m.Msg == WM_NCMOUSEMOVE)
|
115
115
|
{
|
116
116
|
Point current;
|
117
|
-
var control = Control.FromHandle(m.HWnd);
|
118
|
-
if (
|
117
|
+
if (m.Msg == WM_NCMOUSEMOVE)
|
118
|
+
{
|
119
|
-
current = panel1.PointToClient(
|
119
|
+
current = panel1.PointToClient(new Point(m.LParam.ToInt32()));
|
120
|
+
}
|
120
121
|
else
|
122
|
+
{
|
123
|
+
var control = Control.FromHandle(m.HWnd);
|
124
|
+
if (control != null)
|
125
|
+
current = panel1.PointToClient(control.PointToScreen(new Point(m.LParam.ToInt32())));
|
126
|
+
else
|
121
|
-
|
127
|
+
current = panel1.PointToClient(Cursor.Position);
|
128
|
+
}
|
122
129
|
//Debug.Print("WM_MOUSEMOVE: {0}", current);
|
123
130
|
if (panel1.ClientRectangle.Contains(current))
|
124
131
|
{
|
4
マウスを素早く操作してパネルを通り抜けた際に反応しない問題に対処してみました。(文面修正)
answer
CHANGED
@@ -111,7 +111,7 @@
|
|
111
111
|
{
|
112
112
|
const int WM_MOUSEMOVE = 0x0200;
|
113
113
|
const int WM_NCMOUSEMOVE = 0x00A0;
|
114
|
-
if (
|
114
|
+
if (m.Msg == WM_MOUSEMOVE || m.Msg == WM_NCMOUSEMOVE)
|
115
115
|
{
|
116
116
|
Point current;
|
117
117
|
var control = Control.FromHandle(m.HWnd);
|
3
マウスを素早く操作してパネルを通り抜けた際に反応しない問題に対処してみました。(文面修正)
answer
CHANGED
@@ -70,7 +70,9 @@
|
|
70
70
|
[https://github.com/atata0319/teratail130742](https://github.com/atata0319/teratail130742)
|
71
71
|
|
72
72
|
---
|
73
|
-
takabosoftさんが指摘されている案2に対応してみました。コーディングのコストはかなり上がった印象になりますね。Panelの派生クラスとして共通の部品として実装されているのであれば、ありかなと思います。線分の交差判定には別のサイトのサンプルを使用しています。
|
73
|
+
takabosoftさんが指摘されている案2に対応してみました。コーディングのコストはかなり上がった印象になりますね。Panelの派生クラスとして共通の部品として実装されているのであれば、ありかなと思います。線分の交差判定には別のサイトのサンプルを使用しています。
|
74
|
+
|
75
|
+
可能な限り Win32 API を直接使用するのを避けるためにキャプチャーやフックに頼らない方法で実装してあります。タイマー処理を削除したかったのですが、前述の制限によりフォーム外に移動した際の処理を記述するのが難しいので諦めました。
|
74
76
|
```C#
|
75
77
|
public partial class Form1 : Form, IMessageFilter
|
76
78
|
{
|
@@ -198,4 +200,5 @@
|
|
198
200
|
return tc * td < 0 && ta * tb < 0;
|
199
201
|
}
|
200
202
|
}
|
201
|
-
```
|
203
|
+
```
|
204
|
+
Github には検証用プロジェクトを追加してあります。
|
2
マウスを素早く操作してパネルを通り抜けた際に反応しない問題に対処してみました。(文面修正)
answer
CHANGED
@@ -70,7 +70,7 @@
|
|
70
70
|
[https://github.com/atata0319/teratail130742](https://github.com/atata0319/teratail130742)
|
71
71
|
|
72
72
|
---
|
73
|
-
takabosoftさんが指摘されている案2に対応してみました。コーディングのコストはかなり上がった印象になりますね。Panelの派生クラスとして共通の部品として実装されているのであれば、ありかなと思います。線分の交差判定には別のサイトのサンプルを使用しています。
|
73
|
+
takabosoftさんが指摘されている案2に対応してみました。コーディングのコストはかなり上がった印象になりますね。Panelの派生クラスとして共通の部品として実装されているのであれば、ありかなと思います。線分の交差判定には別のサイトのサンプルを使用しています。あと、可能な限り Win32 API を直接使用するのを避けるためにキャプチャーやフックに頼らない方法で実装してあります。
|
74
74
|
```C#
|
75
75
|
public partial class Form1 : Form, IMessageFilter
|
76
76
|
{
|
1
マウスを素早く操作してパネルを通り抜けた際に反応しない問題に対処してみました。
answer
CHANGED
@@ -67,4 +67,135 @@
|
|
67
67
|
なお、TrackMouseEvent 自体はかなり優秀な API でフォーム外のマウスの動作を補足することができます。通常の MouseMove イベントでこれと同程度の処理を実施する場合、他の回答者のコメント通りフックを使用したりマウスをキャプチャーすることになります。いずれの処理も実装するのがちょっと難しいので、タイマーで処理するのがベターであると私は考えています。
|
68
68
|
|
69
69
|
検証用に書いたコードを Github に上げました。
|
70
|
-
[https://github.com/atata0319/teratail130742](https://github.com/atata0319/teratail130742)
|
70
|
+
[https://github.com/atata0319/teratail130742](https://github.com/atata0319/teratail130742)
|
71
|
+
|
72
|
+
---
|
73
|
+
takabosoftさんが指摘されている案2に対応してみました。コーディングのコストはかなり上がった印象になりますね。Panelの派生クラスとして共通の部品として実装されているのであれば、ありかなと思います。線分の交差判定には別のサイトのサンプルを使用しています。
|
74
|
+
```C#
|
75
|
+
public partial class Form1 : Form, IMessageFilter
|
76
|
+
{
|
77
|
+
private bool flag = false;
|
78
|
+
private Point previous;
|
79
|
+
|
80
|
+
public Form1()
|
81
|
+
{
|
82
|
+
InitializeComponent();
|
83
|
+
}
|
84
|
+
|
85
|
+
private void Form1_Load(object sender, EventArgs e)
|
86
|
+
{
|
87
|
+
panel1.Visible = false;
|
88
|
+
}
|
89
|
+
|
90
|
+
private void button1_Click(object sender, EventArgs e)
|
91
|
+
{
|
92
|
+
ShowPanel();
|
93
|
+
}
|
94
|
+
|
95
|
+
private void panel1_MouseEnter(object sender, EventArgs e)
|
96
|
+
{
|
97
|
+
flag = true;
|
98
|
+
}
|
99
|
+
|
100
|
+
private void panel1_MouseLeave(object sender, EventArgs e)
|
101
|
+
{
|
102
|
+
if (!panel1.ClientRectangle.Contains(panel1.PointToClient(Cursor.Position)))
|
103
|
+
{
|
104
|
+
HidePanel();
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
bool IMessageFilter.PreFilterMessage(ref Message m)
|
109
|
+
{
|
110
|
+
const int WM_MOUSEMOVE = 0x0200;
|
111
|
+
const int WM_NCMOUSEMOVE = 0x00A0;
|
112
|
+
if ((m.Msg == WM_MOUSEMOVE || m.Msg == WM_NCMOUSEMOVE) && panel1.Visible)
|
113
|
+
{
|
114
|
+
Point current;
|
115
|
+
var control = Control.FromHandle(m.HWnd);
|
116
|
+
if (control != null)
|
117
|
+
current = panel1.PointToClient(control.PointToScreen(new Point(m.LParam.ToInt32())));
|
118
|
+
else
|
119
|
+
current = panel1.PointToClient(Cursor.Position);
|
120
|
+
//Debug.Print("WM_MOUSEMOVE: {0}", current);
|
121
|
+
if (panel1.ClientRectangle.Contains(current))
|
122
|
+
{
|
123
|
+
flag = true;
|
124
|
+
}
|
125
|
+
else
|
126
|
+
{
|
127
|
+
if (flag)
|
128
|
+
{
|
129
|
+
HidePanel();
|
130
|
+
}
|
131
|
+
else
|
132
|
+
{
|
133
|
+
// 直前の座標と現在の座標を結ぶ線分がパネルの矩形と交差する場合、パネルを閉じる。
|
134
|
+
if (IsIntersected(panel1.ClientRectangle, current, previous))
|
135
|
+
{
|
136
|
+
HidePanel();
|
137
|
+
}
|
138
|
+
}
|
139
|
+
}
|
140
|
+
previous = current;
|
141
|
+
}
|
142
|
+
return false;
|
143
|
+
}
|
144
|
+
|
145
|
+
private void timer1_Tick(object sender, EventArgs e)
|
146
|
+
{
|
147
|
+
var current = panel1.PointToClient(Cursor.Position);
|
148
|
+
// フォーム内から一気にフォーム外に出ていったカーソルはここで処理する。
|
149
|
+
if (IsIntersected(panel1.ClientRectangle, current, previous))
|
150
|
+
{
|
151
|
+
HidePanel();
|
152
|
+
}
|
153
|
+
previous = current;
|
154
|
+
}
|
155
|
+
|
156
|
+
private void ShowPanel()
|
157
|
+
{
|
158
|
+
panel1.Visible = true;
|
159
|
+
timer1.Start();
|
160
|
+
Application.AddMessageFilter(this);
|
161
|
+
previous = panel1.PointToClient(Cursor.Position);
|
162
|
+
}
|
163
|
+
|
164
|
+
private void HidePanel()
|
165
|
+
{
|
166
|
+
flag = false;
|
167
|
+
timer1.Stop();
|
168
|
+
Application.RemoveMessageFilter(this);
|
169
|
+
panel1.Visible = false;
|
170
|
+
}
|
171
|
+
|
172
|
+
private static bool IsIntersected(Rectangle rectangle, Point a, Point b)
|
173
|
+
{
|
174
|
+
// 矩形と線分の交差は各辺と交差しているかどうかで判定する。
|
175
|
+
var lefttop = new Point(rectangle.Left, rectangle.Top); // 左上座標
|
176
|
+
var righttop = new Point(rectangle.Right, rectangle.Top); // 右上座標
|
177
|
+
var leftbottom = new Point(rectangle.Left, rectangle.Bottom); // 左下座標
|
178
|
+
var rightbottom = new Point(rectangle.Right, rectangle.Bottom); // 右下座標
|
179
|
+
if (IsIntersected(a, b, lefttop, leftbottom)) // 左辺
|
180
|
+
return true;
|
181
|
+
if (IsIntersected(a, b, righttop, rightbottom)) // 右辺
|
182
|
+
return true;
|
183
|
+
if (IsIntersected(a, b, leftbottom, rightbottom)) // 下辺
|
184
|
+
return true;
|
185
|
+
if (IsIntersected(a, b, lefttop, righttop)) // 上辺
|
186
|
+
return true;
|
187
|
+
return false;
|
188
|
+
}
|
189
|
+
|
190
|
+
private static bool IsIntersected(Point a, Point b, Point c, Point d)
|
191
|
+
{
|
192
|
+
// https://qiita.com/ykob/items/ab7f30c43a0ed52d16f2
|
193
|
+
// 線分(ab)と線分(cd)が交差しているか判定する。
|
194
|
+
var ta = (c.X - d.X) * (a.Y - c.Y) + (c.Y - d.Y) * (c.X - a.X);
|
195
|
+
var tb = (c.X - d.X) * (b.Y - c.Y) + (c.Y - d.Y) * (c.X - b.X);
|
196
|
+
var tc = (a.X - b.X) * (c.Y - a.Y) + (a.Y - b.Y) * (a.X - c.X);
|
197
|
+
var td = (a.X - b.X) * (d.Y - a.Y) + (a.Y - b.Y) * (a.X - d.X);
|
198
|
+
return tc * td < 0 && ta * tb < 0;
|
199
|
+
}
|
200
|
+
}
|
201
|
+
```
|