VisualStudio 2005 のWTLで開発しています。
コンテキストメニューのように、他のウインドウに触れたりすると
自動で消えるようなウインドウを作成したいと思っています。
このようなウインドウを作る場合にはどのようにしているのでしょうか?
通常のウインドウクラスにマウスのアップイベントとタブキーの入力の
監視をしてウインドウを削除するようにしているのでしょうか?
WM_KILLFOCUS が通知されたらウィンドウ削除するのはどうですか?
HTMLから呼び出すことができるCOMオブジェクトで作った場合に
HTMLのコントロールが変わってもWM_KILLFOCUSなどでメッセージが
来ないようなので、WM_KILLFOCUSだと実現できなさそうです。
WM_ACTIVATE 又は WM_NCACTIVATEでしょう。多分
今回作りたいウインドウは今の所2つありまして、通常の
コンテキストメニューのような場合は
WM_ACTIVATE と WM_NCACTIVATEでうまく行きそうな気がします。
もうひとつはアクティブにならないウインドウの作成を行っています。
こちらは、イメージ的にはサジェスト機能用のウインドウのように
入力は、呼び出し側のウインドウのままになっているものを作成しています。
現状こちらは、マウスキャプチャー機能を使ってできないものか
試している状態です。
マウスのボタンが上がったら、呼び出されたウインドウが
終了するというものをやっているのですが、呼び出し元のウインドウの
最小化ボタンの上でマウスボタンのクリックしても呼び出し元のウインドウが
最小化されません。
マウスキャプチャーをやっているときに最小化ボタンの上にマウスカーソルを
持って行ってもホバー状態にもなりません。
呼び出し元のウインドウに対してPostMessageをやっても
駄目だっでした。
ども、PATIOです。
マウスキャプチャという機能がマウス関連のウインドウメッセージを
キャプチャ中のウインドウに引き込むと言うような事をしているのであれば、
PostMessageをしても駄目かもしれませんね。
私もこのスレッドを見た時にマウスキャプチャで出来ないかなと思ったんですが、
実際のコンテキストメニューは自ウインドウ以外のところにマウスを持って行った時に
下のウインドウのコントロールに反応しているみたいだったのでキャプチャでは
駄目そうだなと思いました。
マウスキャプチャやってしまうとマウス関係のウインドウメッセージが根こそぎ
設定したウインドウに来るようになるのでキャプチャしたウインドウ以外は
反応できなくなったと思ったからです。
マウスのウインドウメッセージを受け取りつつ、下のウインドウにも流すような事が
出来ないと本来のコンテキストメニューみたいな動きは難しいかもしれないですね。
MSDNに、Scribbleサンプルがあります。
確か、チュートリアルもあったと思います。(未確認)
そのサンプルに、マウスキャプチャー等の部分の記述があります。
うーん、メッセージがだめだとなると、僕が思いつくのは、
処理ルーチンを「WaitForSingleObject」で待機させる。
マウスのボタンが上がったところでイベントをイネーブルにする。
ここから処理ルーチン
フォーカス・アクティブ等の履歴をとっといて最後にアクティブになった目的の
ウインドウを終了する。
「かな?」と思いますがどうですか?
お世話になっております。
>MSDNに、Scribbleサンプルがあります。
>確か、チュートリアルもあったと思います。(未確認)
>そのサンプルに、マウスキャプチャー等の部分の記述があります。
Scribble のサンプルを見てみましたが、通常の自分のウインドウに飛んでくる
マウスのイベントを処理しているだけのようです。
このやり方だと、他のウインドウでマウスを押されたときのイベントなど
取得できないと思います。
>フォーカス・アクティブ等の履歴をとっといて最後にアクティブになった目的の
>ウインドウを終了する
自分もこの方法も考えてみたのですが、この方法だと、あるボタンの上に
マウスを持っていったらツールチップが表示されたり、ボタンがホバー状態の
描画になったり、リンクの上に持っていったらカーソルが変わるなどの
処理を実現することができないので、辞めました。
最小化ボタンや最大化ボタンなどは、ホバー状態にならなくても
ボタンを押したときにその動きをしてくれればそれでも良いかなと思っているのですが
自分が表示したウインドウや呼び出し元のウインドウで、ホバー状態になったり
カーソルが変わらなかったりするという状態は解決したいです。
メニューのようなウィンドウはこんな感じです
SetCapture(hWnd); // hWnd:オーナー
hwwndPopup = CreateWindow(,,,WS_POPOP...);
SetWindowPos(hwndPopup,...,SWP_NOACTIVATE | SWP_SHOWWINDOW);
loop(GetMessage()) //モーダルループ
{
case WM_KEYDOWN:
case WM_KEYUP:
エスケープキーを処理
ループ脱出
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
ループ脱出
}
ReleaseCapture();
オーナーのWndProcで
case WM_CAPTURECHANGED:
if(hwndPopup)
DestroyWindow(hwndPopup)
//モーダルループが必要な理由は、フォーカスが移動していないからです
-------------------------------------
ご要望のwindowは上記を改良し、
キャプチャー&モーダルループの替わりに
自スレッドへのWindowsHook(dll不要)で可能と思います
(オーナーが非アクティブになった時の処理も必要です)
//hookが必要な理由 (例)キーボードからシステムメニュー -->移動を選択で
//SysCommandのモーダルループが始まるからです
--------------------------------------
いずれにせよ、オーナーがアクティブの時のみ動作します
(非アクティブのCaptureの動作は面白いです)
あと、メニューバーのホバー、タイトルバー右隅のボタン、同ツールチップ
それぞれ歴史が違い、処理の場所も違っているようです
訂正です
>>オーナーのWndProcで
>>case WM_CAPTURECHANGED:
>> if(hwndPopup)
>> DestroyWindow(hwndPopup)
これを取り消し
モーダルループを脱出した時にReleaseCaptureの直前で
DestroyWindow(hwndPopup);~
してください
あと、
WM_CANCLEMODE, WM_CAPTURECHANGEDでループを脱出するように実装したほうが安心です