第36章 ウィンドウのサブクラス化 その1


さて、前回・前々回と作ったプログラムをもう少し改良 してみましょう。名前のエジットコントロールにフォーカスが ある時(キャレットが点滅しているとき)タブーキーとか、下矢印 カーソルキーを押しても、何も反応がありませんでした。 今回は、名前のところにフォーカスがある時、タブキーまたは 下矢印キー(正式な名前は何というのでしょう?)を押すと フォーカスが生年(西暦)に移動するように作り替えます。 フォーカスが生年(西暦)にあるときは上矢印またはタブキーで 名前の方に移動するようにします。

一体どうすればよいのでしょうか。

ウィンドウプロシージャでWM_KEYDOWNを捕まえればいい。

ブー。残念でした。ウィンドウプロシージャでWM_KEYDOWNを 捕まえても、親ウィンドウに対してキーが押されたことを知ることができても エジットコントロールでのキー押下はわかりません。エジットコントロールは 親とは独立した子供ウィンドウ(?)です。その証拠に自分のウィンドウハンドル を持っています。このウィンドウのプロシージャでWM_KEYDOWNを 捕まえなくてはいけません。

エー、そんなプロシージャ何処にもないよ!

はい。プログラマがいちいち標準コントロールのプロシージャを 書かなくてもいいように内部で自動的に処理されています。 でも、どうしても自分で処理したいメッセージがあるときは特別な 方法があります。ウィンドウのサブクラス化 と呼ばれる方法です。実は、筆者はこれが大好きなのです。

ウィンドウのサブクラス化は別名「メッセージの横取り」とも呼ばれます。 本来のプロシージャに行くはずのメッセージを「横取り」して、 自分で好きなように処理を行うことができます。上の例でいえば本来 エジットコントロール(ウィンドウ)のプロシージャに行くはずのメッセージを 別なところで取ってしまい、そこで処理を行います。 これは、元々のプロシージャに機能を追加する、というように善意に 解釈することもできます。

まず、氏名のエジットコントロール(ウィンドウ)をサブクラス化します。 そして、その中でWM_KEYDOWNメッセージの処理をします。 しかし、このウィンドウに来るすべてのメッセージを処理していたのでは 大変です。自分で処理しないメッセージは元々のプロシージャに任せることに します。(要するにおいしい所だけ取ってしまう。あなたの会社にも そんな人いませんか?

では、具体的な方法を解説します。

1.GetWindowLongで元々のプロシージャのアドレス(FARPROC)を取得する。   具体的には、 FARPROC Org_WndProc; Org_WndProc = (FARPROC)GetWindowLong(サブクラス化するウィンドウのハンドル, GWL_WNDPROC); 2.サブクラス化の実行   SetWindowLong(サブクラス化するウィンドウのハンドル, GWL_WNDPROC, (LONG)新しいプロシージャ); 3.必要がなくなったらサブクラス化の解除   SetWindowLong(サブクラス化したウィンドウのハンドル, GWL_WNDPROC, (LONG)Org_WndProc); 4.新しいプロシージャの中では、 自分で処理しないものは、CallWindowProcで元のプロシージャに押しつける   return (CallWindowProc(Org_WndProc, サブクラス化したウィンドウのハンドル, msg, wp, lp));   自分で処理したものは、0を返します。

と、まあこんな風に行います。GetWindowLong関数はすでにインスタンスハンドルを取得するところで 何回も出てきました。第19章を参照してください。

それと、16ビット版では少しやり方が異なります。 2の新しいプロシージャを直接登録するのではなく

FARPROC newproc, orgproc; newproc = MakeProcInstance((FARPROC)新しいプロシージャ, インスタンスハンドル); SetWindowLong(サブクラス化するウィンドウのハンドル, GWL_WNDPROC, (LONG)newproc);

というようにします。また、解除するときは元のプロシージャに戻して、 さらにFreeProcInstance((FARPROC)newproc);を実行します。32ビットの方が簡単ですね。



では、具体的にプログラムを考えてみます。まず、エジットコントロール(ウィンドウ)は 2つありますから、これらをサブクラス化します。あたらいいプロシージャを それぞれ、MyWndProc1, MyWndProc2とします。

MyWndProc1でWM_KEYDOWNメッセージを捕まえたら押されたキーを調べます。 もし、タブキーか下矢印ならフォーカスを次のウィンドウに移します。 それ以外のキーなら、元々のプロシージャに戻します。

MyWndProc2でも同じようなことをします。タブキーか、上矢印ならフォーカスを 変更します。

フォーカスの変更(セット)はSetFocus関数で行います。

HWND SetFocus( HWND hWnd // 新しくセットされるウィンドウのハンドル );

戻り値は、直前のフォーカスを持っていたウィンドウのハンドルです。失敗は NULLを返します。

具体的なプログラムは次章でやります。今回はサブクラス化の概念の 解説でした。


[SDK Index] [総合Index] [Previous Chapter] [Next Chapter]

Update May/22/1997 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。