Delphi 6 Pro SP2 (Win 98) を使用しています。
フォーム上にボタンやラベルを配置しました。
Form.MouseMoveイベントを使用してマウスポインタの移動を監視すると、
ボタンやラベル上にマウスポインタが移動したときに MouseMoveイベントが
発生しないことが分かりました。
やりたいことは
・フォーム上のマウスポインタの出入りを知りたい
(ラベルAに Enter/Leave と表示したい)
・マウスポインタの位置を知りたい (フォーム上のみ)
(ラベルBにマウスポインタの座標を表示したい)
・MouseMoveのようなイベントで、上記を実現したい
(リアルタイムで表示更新したい)
また、動的にラベルを追加したりしたいので、各コントロールのイベントを
記述するような形は避けたいです。
色々と調べているのですが、どのようにすれば実現できるのか
分からない状態です。
ヒントだけでもいただけませんでしょうか。
すみませんが、よろしくお願いいたします。
CM_MOUSEENTERメッセージを使えば出来るかと思います。
この掲示板でも何度か出ているので、CM_MOUSEENTERで検索してみてはどうでしょう。
にしのさん、ありがとうございます。FAQで申し訳ございません。
早速検索してみたのですが・・・
私のイメージでは、CM_MouseEnter/Leaveは、各コントロールの
イベントハンドラを記述する必要があるように思えてしまうのです。
(共通化する手段がわかりません。(^-^;)
できれば、後でコントロールを追加しても、イベントハンドラを追加しないで
動作するようなものにしたいです。
現状では、
https://www.petitmonte.com/bbs/answers?question_id=1040
を応用させれば実現できそうな気がしています。
これから試してみたいと思います。
ありがとうございました。
リアルタイムにマウスポインタの位置を知るというのを読み飛ばしていました。
すみません。
一取得は、TApplicationEventsのOnMessageを使えば、以下のようにして出来ます。
var
pt: TPoint;
begin
if Msg.message = WM_MOUSEMOVE then
begin
GetCursorPos(pt);
Label1.Caption := '(' + IntToStr(pt.X) + ',' + IntToStr(pt.Y) + ')';
end;
end;
OnMessageイベントは、たくさんのメッセージが飛んでくるので、扱いには注意です。
にしのさん、ありがとうございます。
にしのさんに頂いたアドバイスと過去ログから、以下のように作成しました。
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
var Handled: Boolean);
var
AMouse: TMouse;
APos : TPoint;
begin
if Msg.message = WM_MOUSEMOVE then begin
AMouse := TMouse.Create;
APos := AMouse.CursorPos;
APos := ScreenToClient(APos);
Label1.Caption := IntToStr(APos.X) + ', ' + IntToStr(APos.Y);
end;
end;
Enter/Leaveは、過去ログにありましたように CM_MouseEnterで
タイマを起動し、PtInRect()を使用して Leaveを判別するようにしました。
これでやりたいことは実現できたのですが、すみません、もう1つだけ
教えて頂けませんでしょうか。
>OnMessageイベントは、たくさんのメッセージが飛んでくるので、
>扱いには注意です。
とのことですが、具体的にどのような点について注意する必要が
あるのでしょうか。
すみませんが、よろしくお願いいたします。
> AMouse := TMouse.Create;
> APos := AMouse.CursorPos;
TMouse のインスタンスを作成する必要はないよ。Free してないし。
Controls.pas の Mouse オブジェクトを使う。
APos := Mouse.CursorPos;
> 具体的にどのような点について注意する必要があるのでしょうか。
重い処理をしないように、くらい。
上のように AMouse.Free がないと大変。
jokさん、ありがとうございます。
Mouseオブジェクトを使用するように変更しました。
Createしたら Freeですね。ありがとうございました。
> TMouse.Create
ヘルプにあるとおり、TMouseを生成してはいけません。どうなるかはわかりませんけど、するべきではなさそうです。
Mouseオブジェクトは、確か休止状態に入ったり、復帰したりするとき、参照しようとするとエラーが起こるはず。
(GetCursorPosが失敗するので)
ここではWM_MOUSEMOVEの中なので大丈夫かもしれないですけど、GetCursorPosを使って、得た値がInvalidPointでないときに処理を行うような風にしたほうがいいかも。。
> 具体的にどのような点について注意する必要があるのでしょうか。
まあ、冗長な処理(ほかでもできるようなことをするとか)はしないほうがいい…でしょうね。グローバルフックとかじゃないので、そこまで気を使う必要もないでしょうけど。
if文の外で何か処理をしないように、でしょうかね。
OnMessageイベントは、アプリケーション上のメッセージの個数分実行されますから、関係ない処理をすると—わかりますね。
たかみちえさん、ありがとうございます。
作成したコードも、気がついたら TMouseを宣言しないで
動作していた部分がありました。
ヘルプを見ているうちに Mouse変数というのを見つけ、
Create/Freeする必要ないじゃんってことになりました。
GetCursorPosの前に tryが必要ということでしょうか?
また InvalidPointというのは、負の値などの定数ですか?
もしよろしければご教授下さい。
フックした部分は、できるだけ軽くするようにしたいと思います。
グローバルフックはやったことがありませんが、面白そうですね。
ありがとうございました。
> GetCursorPosの前に tryが必要ということでしょうか?
えー、Win98ではその問題には出会わないかもしれませんけど…。
Mouseオブジェクトの関数でマウス座標を取得しようとすると、
マウス座標の取得に失敗した場合、エラーメッセージがでてしまいます。
タイマーや今回のメッセージループ内のようなところでつかうと、
エラーが連続して起こり、画面上エラーだらけ…という事態に陥ることがあります。
try ... except end; で囲んでも何とかできますけど、
ここはAPIのGetCursorPosを直接呼び出して使った方が早いのではないか?と、おもったわけです。
> InvalidPoint
まずヘルプを読んでみてください。Delphiの関数なので載っています。(GetCursorPosは、同時にインストールしているはずのWinAPIヘルプや、ネット上のページを参考にしてください)
たかみちえさん、ありがとうございます。
>えー、Win98ではその問題には出会わないかもしれませんけど…。
細かいことですみませんが、NT系で発生するとかでしょうか?
>Mouseオブジェクトの関数でマウス座標を取得しようとすると、
>マウス座標の取得に失敗した場合、エラーメッセージがでてしまいます。
情報ありがとうございます。
Mouse変数の CursorPosプロパティを取得するときも Mouseオブジェクトの
関数をコールすると考えると、その可能性を感じます。
APIの直接呼び出しの方法は、これから勉強します。
> InvalidPoint
調査が不足しておりました。すみません。
ありがとうございました。
ツイート | ![]() |