マウスの左ボタンが押されているとCM_MouseLeaveが発生しない件


km  2020-07-29 22:14:45  No: 148964

 いつもお世話になります。表記の件について質問させてください。
(簡単にするため、Memo1(TMemo)がalClientの状態で貼られたフォームで
ご説明します。実際にはたくさんのコンポーネントが貼られていますが。)

 Memo1上でマウスをドラッグしている最中、Memo1や、Form自体の外
にマウスが出たことを検知するため、従来は次のメッセージ処理に頼って
いました。(Delphi6の頃)

    procedure CMMouseLeave(var Msg: TMessage);
      message CM_MouseLeave;

 しかし、Delphi10.3+Windows10の環境の場合、マウスの左ボタンが押された
状態ですと、このメッセージは飛んでこないことが分かりました。

 検索してみると、MouseMoveイベントで処理するとよい、との書き込みを
見つけましたので、試行錯誤の結果、暫定的に以下のように処理しようとして
います。もし、CM_MouseLeaveを処理できる方法や、それに近いスムーズな
書き方などご存じの方がいらっしゃいましたらお教えいただけますでしょうか。
(コードの見通しをよくするため、従来と同様、CM_MouseLeaveのような
メッセージ処理で判別できればありがたいと思っています。)
お手間をおかけいたしますが、どうぞよろしくお願いいたします。

procedure TForm1.Memo1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  R: TRect;
  CP, P1, P2: TPoint;
begin
  P1 := Memo1.ClientRect.TopLeft;
  P2 := Memo1.ClientRect.BottomRight;
  R := Rect(P1.X, P1.Y, P2.X, P2.Y);
  CP := TPoint.Create(X, Y);

  if PtInRect(R, CP) then
    Caption := 'In'
  else
    Caption := 'Out';
end;


Mr.XRAY  2020-08-02 14:40:19  No: 148966

これもレスしにくい内容ですね.
方向が「不変」ではなく「変化」しそうな気配ですが・・・

>(コードの見通しをよくするため、従来と同様、CM_MouseLeave のような

従来と同様というのは Delphi 6 の頃のことだと思いますが,
Delphi 6 でもマウスボタン押下状態の時は CM_MouseLeave メッセージは
送られてきません.ボタンを離せば送られてきます.
つまり,この動作仕様は Delphi 6 以降で「不変」のハズです.

Delphi 6 で期待通りの動作なのであれば,何か処理をしていると思われます.
それと同じにしてみたらどうでしょう.

※ Delphi 6 については,
※ Windows 10 + Delphi 6 Pro(UP2) で新規プロジェクトを作成して確認しました.


Mr.XRAY  2020-08-03 22:40:00  No: 148969

もう 1 つ.

> 暫定的に以下のように処理しようとしています。
 (改行変更しました)
  
実際に動作確認したのでしょうか ?
提示のコードが Memo1 の OnMouseMove イベントだとすると,
このイベントは,マウスカーソルが Memo1 の領域内にないと発生しません.
したがって,マウスカーソルが Memo1 の領域内にあるか,領域外にあるかの
判定はできないと思いますが.


AAA  2020-08-04 19:28:14  No: 148970

procedure TControl.WMLButtonDown(var Message: TWMLButtonDown);
begin
  SendCancelMode(Self);
  inherited;
  if csCaptureMouse in ControlStyle then
    MouseCapture := True;
  if csClickEvents in ControlStyle then
    Include(FControlState, csClicked);
  DoMouseDown(Message, mbLeft, []);
end;
ここで MouseCapture := True; になってるからかな


AAA  2020-08-04 19:33:18  No: 148971

type
// MouseCapture が Protected なので
  TMemo = class(vcl.stdCtrls.TMemo);

procedure TForm1.Memo1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
    Memo1.MouseCapture := False;
end;


km  2020-08-04 22:14:29  No: 148973

書き込みありがとうございます。
Mr.XRAY様、delphi6で作ったコードをコピペで入れると、delphi10.3では、mouseleaveがうまく動きませんでした。
ここは自分ではよく使う機能で、新規プロジェクトに雛形として保存していたものからまるまる写していたので、確認漏れというのは考えにくいとは思っています。
ただ、今回自分が提示させていただいたコードも、時間をかけて動作確認を行なって、動いたことを確認したつもりではおります。マウスを数ピクセル単位で動かしながら時間をかけて細かくみていたので、それなりに自信はありますが、100%誤りがないかというと、誤りもありえるかもしれません。
もう一度後で確認してみます。

AAA様、ホームページを検索している中で、ご指摘くださったCaptureという単語を確かに見かけた記憶があります。
その書き込みを見て、Delphi6とDelphi10では、Captureという部分の処理が違うのではないかと思ったのかもしれません。
これがあるのとないのとでは、どう処理が違ってくるのかは理解しておりませんが、マウスを離さない限りは、元のコントロールでの処理が有効なのかな?とも思える書き込みだったように感じ、mousemoveの処理を書いたという流れだったと思います。
あとで実際試してみたいと思います。
分かりにくい質問に対してフォローしていただき、ありがとうございます。


km  2020-08-04 22:27:11  No: 148974

確か、このページなどを参考にしたと思います。

https://stackoverflow.com/questions/20525833/delphi-xe2-cmmouseleave-not-triggered-on-tcustomcontrol

以下は引用です。
The mouse is captured when you press the left button. Hence the control will receive mouse move messages (WM_MOUSEMOVE), even if the mouse is outside the control. It will receive mouse leave message when the button is released. I highly doubt this is not the case with D5.


Mr.XRAY  2020-08-04 23:02:18  No: 148975

Mr.XRAY です.
経過から考えると,あまり参考にはならないかも知れませんが.

[ マウスカーソルのコントロール領域外への移動を検出 ] 
http://mrxray.on.coocan.jp/Delphi/Others/MouseLeave.htm


Mr.XRAY  2020-08-04 23:04:36  No: 148976

ついでにもう 1 つ.

[ マウスカーソルのフォーム上の位置 ] 
http://mrxray.on.coocan.jp/Delphi/Others/MousePos_App.htm


km  2020-08-05 17:35:02  No: 148978

Mr.XRAY様
先日からここではずっとお世話になりっぱなしですね。
ここまでしてくださって、本当に頭の下がる、もったいない、ありがたい気持ちでいっぱいです。
captureの件は、おそらく自分が求めていた答えです。ただ、エンバカデロ様がこのような動作に変更した理由が何かあるはずで、それが十分調べきれそうになかったこともあり、基本的には自分が理解できるコードの範疇で対応しようということで、上記のコードを書いておりました。
時間が取れた時点で、まずは自分が理解し切れるコードの部分から試していって、望む動作になった時点で自分の正解にしようと思います。
このたびはわざわざ記事にまでしてくださり、誠にありがとうございました。大変助かりました。


Mr.XRAY  2020-08-15 11:27:57  No: 148996

解決のチェックが中々付かないようですので,
以下の記事を追加しました.                               

[ 04_CM_MOUSELEAVE の挙動を Delphi 7 以前と同じにする ]
http://mrxray.on.coocan.jp/Delphi/Others/MouseLeave.htm#04


Mr.XRAY  2020-08-15 23:10:45  No: 149001

>[ 04_CM_MOUSELEAVE の挙動を Delphi 7 以前と同じにする ]
http://mrxray.on.coocan.jp/Delphi/Others/MouseLeave.htm#04

の記事を削除しました.
確かに CM_MOUSELEAVE の挙動は Delphi 7 以前と同じにはなるのですが,
CM_MOUSEENTER も修正しなければなりません.
これは結構面倒なようです.
そもそも Delphi 7 以前の CM_MOUSEENTER のメッセージ処理は,
マウスドラッグ操作の時の挙動が怪しい・・・


※返信する前に利用規約をご確認ください。








  このエントリーをはてなブックマークに追加