回答編集履歴

5

WM_NCMOUSEMOVEの処理が正しくなかったのを修正

2018/06/14 15:35

投稿

atata0319
atata0319

スコア881

test CHANGED
@@ -230,15 +230,29 @@
230
230
 
231
231
  Point current;
232
232
 
233
- var control = Control.FromHandle(m.HWnd);
234
-
235
- if (control != null)
233
+ if (m.Msg == WM_NCMOUSEMOVE)
234
+
236
-
235
+ {
236
+
237
- current = panel1.PointToClient(control.PointToScreen(new Point(m.LParam.ToInt32())));
237
+ current = panel1.PointToClient(new Point(m.LParam.ToInt32()));
238
+
239
+ }
238
240
 
239
241
  else
240
242
 
243
+ {
244
+
245
+ var control = Control.FromHandle(m.HWnd);
246
+
247
+ if (control != null)
248
+
249
+ current = panel1.PointToClient(control.PointToScreen(new Point(m.LParam.ToInt32())));
250
+
251
+ else
252
+
241
- current = panel1.PointToClient(Cursor.Position);
253
+ current = panel1.PointToClient(Cursor.Position);
254
+
255
+ }
242
256
 
243
257
  //Debug.Print("WM_MOUSEMOVE: {0}", current);
244
258
 

4

マウスを素早く操作してパネルを通り抜けた際に反応しない問題に対処してみました。(文面修正)

2018/06/14 15:35

投稿

atata0319
atata0319

スコア881

test CHANGED
@@ -224,7 +224,7 @@
224
224
 
225
225
  const int WM_NCMOUSEMOVE = 0x00A0;
226
226
 
227
- if ((m.Msg == WM_MOUSEMOVE || m.Msg == WM_NCMOUSEMOVE) && panel1.Visible)
227
+ if (m.Msg == WM_MOUSEMOVE || m.Msg == WM_NCMOUSEMOVE)
228
228
 
229
229
  {
230
230
 

3

マウスを素早く操作してパネルを通り抜けた際に反応しない問題に対処してみました。(文面修正)

2018/06/13 17:40

投稿

atata0319
atata0319

スコア881

test CHANGED
@@ -142,7 +142,11 @@
142
142
 
143
143
  ---
144
144
 
145
- takabosoftさんが指摘されている案2に対応してみました。コーディングのコストはかなり上がった印象になりますね。Panelの派生クラスとして共通の部品として実装されているのであれば、ありかなと思います。線分の交差判定には別のサイトのサンプルを使用しています。あと、可能な限り Win32 API を直接使用するのを避けるためにキャプチャーやフックに頼らない方法で実装してあります。
145
+ takabosoftさんが指摘されている案2に対応してみました。コーディングのコストはかなり上がった印象になりますね。Panelの派生クラスとして共通の部品として実装されているのであれば、ありかなと思います。線分の交差判定には別のサイトのサンプルを使用しています。
146
+
147
+
148
+
149
+ 可能な限り Win32 API を直接使用するのを避けるためにキャプチャーやフックに頼らない方法で実装してあります。タイマー処理を削除したかったのですが、前述の制限によりフォーム外に移動した際の処理を記述するのが難しいので諦めました。
146
150
 
147
151
  ```C#
148
152
 
@@ -399,3 +403,5 @@
399
403
  }
400
404
 
401
405
  ```
406
+
407
+ Github には検証用プロジェクトを追加してあります。

2

マウスを素早く操作してパネルを通り抜けた際に反応しない問題に対処してみました。(文面修正)

2018/06/13 17:29

投稿

atata0319
atata0319

スコア881

test CHANGED
@@ -142,7 +142,7 @@
142
142
 
143
143
  ---
144
144
 
145
- takabosoftさんが指摘されている案2に対応してみました。コーディングのコストはかなり上がった印象になりますね。Panelの派生クラスとして共通の部品として実装されているのであれば、ありかなと思います。線分の交差判定には別のサイトのサンプルを使用しています。
145
+ takabosoftさんが指摘されている案2に対応してみました。コーディングのコストはかなり上がった印象になりますね。Panelの派生クラスとして共通の部品として実装されているのであれば、ありかなと思います。線分の交差判定には別のサイトのサンプルを使用しています。あと、可能な限り Win32 API を直接使用するのを避けるためにキャプチャーやフックに頼らない方法で実装してあります。
146
146
 
147
147
  ```C#
148
148
 

1

マウスを素早く操作してパネルを通り抜けた際に反応しない問題に対処してみました。

2018/06/13 17:26

投稿

atata0319
atata0319

スコア881

test CHANGED
@@ -137,3 +137,265 @@
137
137
  検証用に書いたコードを Github に上げました。
138
138
 
139
139
  [https://github.com/atata0319/teratail130742](https://github.com/atata0319/teratail130742)
140
+
141
+
142
+
143
+ ---
144
+
145
+ takabosoftさんが指摘されている案2に対応してみました。コーディングのコストはかなり上がった印象になりますね。Panelの派生クラスとして共通の部品として実装されているのであれば、ありかなと思います。線分の交差判定には別のサイトのサンプルを使用しています。
146
+
147
+ ```C#
148
+
149
+ public partial class Form1 : Form, IMessageFilter
150
+
151
+ {
152
+
153
+ private bool flag = false;
154
+
155
+ private Point previous;
156
+
157
+
158
+
159
+ public Form1()
160
+
161
+ {
162
+
163
+ InitializeComponent();
164
+
165
+ }
166
+
167
+
168
+
169
+ private void Form1_Load(object sender, EventArgs e)
170
+
171
+ {
172
+
173
+ panel1.Visible = false;
174
+
175
+ }
176
+
177
+
178
+
179
+ private void button1_Click(object sender, EventArgs e)
180
+
181
+ {
182
+
183
+ ShowPanel();
184
+
185
+ }
186
+
187
+
188
+
189
+ private void panel1_MouseEnter(object sender, EventArgs e)
190
+
191
+ {
192
+
193
+ flag = true;
194
+
195
+ }
196
+
197
+
198
+
199
+ private void panel1_MouseLeave(object sender, EventArgs e)
200
+
201
+ {
202
+
203
+ if (!panel1.ClientRectangle.Contains(panel1.PointToClient(Cursor.Position)))
204
+
205
+ {
206
+
207
+ HidePanel();
208
+
209
+ }
210
+
211
+ }
212
+
213
+
214
+
215
+ bool IMessageFilter.PreFilterMessage(ref Message m)
216
+
217
+ {
218
+
219
+ const int WM_MOUSEMOVE = 0x0200;
220
+
221
+ const int WM_NCMOUSEMOVE = 0x00A0;
222
+
223
+ if ((m.Msg == WM_MOUSEMOVE || m.Msg == WM_NCMOUSEMOVE) && panel1.Visible)
224
+
225
+ {
226
+
227
+ Point current;
228
+
229
+ var control = Control.FromHandle(m.HWnd);
230
+
231
+ if (control != null)
232
+
233
+ current = panel1.PointToClient(control.PointToScreen(new Point(m.LParam.ToInt32())));
234
+
235
+ else
236
+
237
+ current = panel1.PointToClient(Cursor.Position);
238
+
239
+ //Debug.Print("WM_MOUSEMOVE: {0}", current);
240
+
241
+ if (panel1.ClientRectangle.Contains(current))
242
+
243
+ {
244
+
245
+ flag = true;
246
+
247
+ }
248
+
249
+ else
250
+
251
+ {
252
+
253
+ if (flag)
254
+
255
+ {
256
+
257
+ HidePanel();
258
+
259
+ }
260
+
261
+ else
262
+
263
+ {
264
+
265
+ // 直前の座標と現在の座標を結ぶ線分がパネルの矩形と交差する場合、パネルを閉じる。
266
+
267
+ if (IsIntersected(panel1.ClientRectangle, current, previous))
268
+
269
+ {
270
+
271
+ HidePanel();
272
+
273
+ }
274
+
275
+ }
276
+
277
+ }
278
+
279
+ previous = current;
280
+
281
+ }
282
+
283
+ return false;
284
+
285
+ }
286
+
287
+
288
+
289
+ private void timer1_Tick(object sender, EventArgs e)
290
+
291
+ {
292
+
293
+ var current = panel1.PointToClient(Cursor.Position);
294
+
295
+ // フォーム内から一気にフォーム外に出ていったカーソルはここで処理する。
296
+
297
+ if (IsIntersected(panel1.ClientRectangle, current, previous))
298
+
299
+ {
300
+
301
+ HidePanel();
302
+
303
+ }
304
+
305
+ previous = current;
306
+
307
+ }
308
+
309
+
310
+
311
+ private void ShowPanel()
312
+
313
+ {
314
+
315
+ panel1.Visible = true;
316
+
317
+ timer1.Start();
318
+
319
+ Application.AddMessageFilter(this);
320
+
321
+ previous = panel1.PointToClient(Cursor.Position);
322
+
323
+ }
324
+
325
+
326
+
327
+ private void HidePanel()
328
+
329
+ {
330
+
331
+ flag = false;
332
+
333
+ timer1.Stop();
334
+
335
+ Application.RemoveMessageFilter(this);
336
+
337
+ panel1.Visible = false;
338
+
339
+ }
340
+
341
+
342
+
343
+ private static bool IsIntersected(Rectangle rectangle, Point a, Point b)
344
+
345
+ {
346
+
347
+ // 矩形と線分の交差は各辺と交差しているかどうかで判定する。
348
+
349
+ var lefttop = new Point(rectangle.Left, rectangle.Top); // 左上座標
350
+
351
+ var righttop = new Point(rectangle.Right, rectangle.Top); // 右上座標
352
+
353
+ var leftbottom = new Point(rectangle.Left, rectangle.Bottom); // 左下座標
354
+
355
+ var rightbottom = new Point(rectangle.Right, rectangle.Bottom); // 右下座標
356
+
357
+ if (IsIntersected(a, b, lefttop, leftbottom)) // 左辺
358
+
359
+ return true;
360
+
361
+ if (IsIntersected(a, b, righttop, rightbottom)) // 右辺
362
+
363
+ return true;
364
+
365
+ if (IsIntersected(a, b, leftbottom, rightbottom)) // 下辺
366
+
367
+ return true;
368
+
369
+ if (IsIntersected(a, b, lefttop, righttop)) // 上辺
370
+
371
+ return true;
372
+
373
+ return false;
374
+
375
+ }
376
+
377
+
378
+
379
+ private static bool IsIntersected(Point a, Point b, Point c, Point d)
380
+
381
+ {
382
+
383
+ // https://qiita.com/ykob/items/ab7f30c43a0ed52d16f2
384
+
385
+ // 線分(ab)と線分(cd)が交差しているか判定する。
386
+
387
+ var ta = (c.X - d.X) * (a.Y - c.Y) + (c.Y - d.Y) * (c.X - a.X);
388
+
389
+ var tb = (c.X - d.X) * (b.Y - c.Y) + (c.Y - d.Y) * (c.X - b.X);
390
+
391
+ var tc = (a.X - b.X) * (c.Y - a.Y) + (a.Y - b.Y) * (a.X - c.X);
392
+
393
+ var td = (a.X - b.X) * (d.Y - a.Y) + (a.Y - b.Y) * (a.X - d.X);
394
+
395
+ return tc * td < 0 && ta * tb < 0;
396
+
397
+ }
398
+
399
+ }
400
+
401
+ ```