1998/03/09
Visual C++/MFC Tips No.2

タイトルバー以外をドラッグしても、ウィンドウが動かせるようにする


タイトルバーなしのウィンドウを作ったのはいいが、ウィンドウの移動はどうするのか?。 なんて思ったことがあると思います。(なんか、強引)
僕は、最近標準のAppWizardを使わないで、アプリケーションクラスのみのスケルトンを作成するCustomWizardを作っておいて、 CWndから直接クラスを派生させて、ウィンドウを作ったりするようになりました。
そうすると、タイトルバーを無くしたり、いろいろなことができます。
今回は、こんな時ウィンドウの移動をどうすればいいのか?そのテクニックを紹介します。でも、結構有名な方法なので、知っている方の方が多いと思います。 ここ以外でも紹介されている方法です。

Windowsはマウスカーソルが動いたりボタンが押されたりすると、 カーソルの下のウィンドウ(もしくはカーソルをキャプチャしているウィンドウ)に WM_NCHITTESTというメッセージを送ります。
ウィンドウはそのとき、カーソルがどこにあるのかという情報を返すのですが、 このとき、カーソルがどこにあるのかに関わらず、HTCAPTIONというタイトルバー上にマウスカーソルが あることを示す値を返してやれば、Windowsはそこをタイトルバーだと認識し、 ウィンドウのどこをドラッグしてもウィンドウを移動することが可能になります。

具体的な方法を紹介します。
ウィンドウクラスとして、CMyWndというCWndから派生したクラスを使うとします。
WM_NCHITTESTを処理するために、OnNcHitTest()をオーバーライドします。
ClassWizardを使っていれば、オーバーライドは簡単です。
ClassWizardのメッセージマップでクラス名にCMyWndを選んで、メッセージ欄のWM_HITTESTをダブルクリックし、OKを押すだけです。

OnNcHitTest()関数がオーバーライドされ、追加されますのでそこに次のような記述をします。

UINT CMyWnd::OnNcHitTest( CPoint point )
{
	return HTCAPTION;
}
これだけです。


おまけ
ここで、引数にpointがありますが、これがメッセージが送られた時点でのマウスカーソルの位置です。
本来は、この情報を元に、今どこにマウスカーソルがあるのかをWindowsに教えるわけです。
Windowsはウィンドウの境界や、最大表示ボタンなどの情報もこのメッセージを送って調べています。
ですから、これを使うといろいろと、Windowsをだますことができるわけです。
この例では、問答無用でHTCAPTIONを返していますが、このままでは問題がでることがあります。
例えば、サイズ変更可能な境界を持つウインドウでも、どこが境界かわからなくなって、ウィンドウの端に マウスカーソルを持っていっても、カーソルの形が変わらなくなってしまいます。
ですから、タイトルバーとして認識させたいところ以外にマウスカーソルがあった場合、基本クラスの OnNcHitTest()関数を呼び出した方がいいかもしれません。

もう1つおまけ
きっとこんなことも知らなかったのは僕だけだと思うのですが、マウスのメッセージというのは、クライアント領域と 非クライアント領域では、送られてくるメッセージが違います。この方法を使ってウィンドウ全体をタイトルバーとして認識させた後に、 マウスのクリックを検出したいと思ったのですが、全部がタイトルバーとして認識されているため、WM_〜BUTTON〜というメッセージやWM_MOUSEMOVEなどの一連のマウス関連のメッセージが 送られてこないので、困ってしまったことがあったのです。
WM_NCHITTESTにたいして、HTCAPTIONを返すと、タイトルバーとして扱われます。
タイトルバーは非クライアント領域ですので、非クライアント領域のためのマウスのイベントのメッセージが送られてくることになります。
非クライアント領域へのメッセージはすべて、WM_NC〜となります。
WM_NCLBUTTONDOWN, WM_NCLBUTTONUP, WM_NCRBUTTONDOWN, WM_NCRBUTTONUPなどがあります。


back
Visual C++ Laboratoryのページへ戻る


back最初のページへ戻る


E-Mail:wbs03748@mail.wbs.ne.jp
質問・感想などのメールはこちらへ。


Copyright(C) 1998 Shingo Nakagawa / e-mail:wbs03748@mail.wbs.ne.jp