ボタンのクラス化(WindowsAPI)

ボタンのクラス化は結構大変・・・。

ボタンが押された時、WM_COMMANDは親ダイアログに通知されるので、親ダイアログのハンドラにそれに対する処理を書けばいい・・・。

しかし、それだと親ダイアログが肥大化しそうなので、各ボタンクラスオブジェクトにそのボタンのイベントハンドラを用意し、そこで処理させてみる・・・。

まず、基底クラスCButtonは、

Button.hが、

Button.cppが、

としている・・・。
CWindowの派生クラスで定義されていて、

CButton::Createは、子ウィンドウとなるボタン用のメンバ関数なので引数がいくつか省略されている・・・。

そして、呼び出しているCWindow::Createも新たな引数を追加・・・。

bProcChangeはデフォルトがFALSEだが、子ウィンドウの場合はTRUEを指定・・・。
すると、OnCreateの実行と、プロシージャの差し替え、が行われる・・・。
"Button"ウィンドウクラスのまま、プロシージャを差し替えてカスタマイズしたいのだが、そうするとOnCreateが呼ばれないのでこのタイミングで・・・。
そして、ウィンドウオブジェクトはm_mapWindowMapで管理・・・。
"Button"元々のウィンドウプロシージャをCallWindowProcで呼ぶ必要があるので、そのプロシージャはm_mapBaseWindowProcMapを用意し、これに登録・・・。

StaticWindowProcもこれに合わせて、

このように変更・・・。

DynamicWindowProcも、

とする・・・。

あ、オリジナルのウィンドウクラスの場合は、

RegisterClassの時にDefWindowProcを登録する・・・。

さて、CDialogのOnInitDialogで、

EnumChildWindowsで子ウィンドウを列挙する・・・。

CreateWindowObjectという関数で、子ウィンドウのウィンドウハンドルやウィンドウクラス名から、子ウィンドウオブジェクトを取得・・・。
それをm_mapChildWindowsMap、m_mapBaseWindowProcMap、m_mapWindowMapに登録・・・。
子ウィンドウマップは、親であるダイアログが破棄される前に、子ウィンドウを一斉に破棄するために使う・・・。

CreateWindowObjectは、

引数でもらったハンドルなどのウィンドウ情報からオブジェクト(この場合はCButton)を作成し返してるだけ・・・。

でこれはオーバーライドできるので、派生のCAboutDialogでは、

例えば、子ウィンドウのリソースIDごとに子ウィンドウオブジェクトを振り分けられる・・・。

DialogBoxParamでダイアログを表示した時、すでに子ウィンドウは生成されていて、ウィンドウハンドルとウィンドウオブジェクトを紐づけるOnCreateみたいな部分がないので、こうやってOnInitDialogで子ウィンドウを列挙して、子ウィンドウごとにウィンドウオブジェクトを作成し紐づけている・・・。

ボタンを押すと、親ダイアログCAboutDialogのOnCommandに来るので、該当する子ウィンドウオブジェクトのChildCommandProcを呼ぶ・・・。

CButtonのChildCommandProcで、HIWORD(wParam)の通知コードがBN_CLICKEDなら、ボタンクリックなので、OnBnClickedを処理・・・。

CUpdateCheckButtonなら、

メッセージボックス・・・。

COKButtonなら、

SendMessageでWM_CLOSEを送って、ダイアログを閉じる・・・。

ちなみに、子ウィンドウの破棄は、

OnCloseでm_mapChildWindowsMapに登録されたものを一斉破棄・・・。

f:id:BG1:20160604111407p:plain

一応、Createでウィンドウ上にボタンを置くこともできる・・・。(この辺はMainWindow参照・・・。)

f:id:BG1:20160604111624p:plain

でも、今回はダイアログ上のボタンをどうクラス化するかという問題だったので・・・。

Test/button/class_button/winapi/src/CButton/CButton at master · bg1bgst333/Test · GitHub