質問: m_check_item; //check_item1.Create(IDC_CHECK_ITEM, this->classToDoDlg); } ``` 備考:完了タブに切り替えて、再びTo Doタブに切り替えた際は期待通り描画されています。 この問題を解決するために以下の仮説を立てて解決できるかどうか試してみました。 仮説:再描画を手動で行う関数を使えば解決できる。 再描画の機能を持つと思われる関数: ・RedrawWindow関数 ・InvalidateRect関数 //領域無効化 UpdateWindow関数 //再描画命令 問題:RedrawWindow関数を使うにしても、InvalidateRect関数を使うにしても、引数のlpcrectに何を設定してよいかわからない。 この問題を解決するために、試しにlpcrectにToDoDlgのウィンドウサイズをポインタで取得できる関数があるか探してみましたが、見つかりませんでした。 解決策を教えて頂けるとありがたいです。どうかよろしくお願い致します。
回答: 大元の問題である **「Enterキーを押下するとタブコントロール上の子ダイアログが再描画されない」** 件に関しては以下が答えになります。 **直接的な答え:** 該当の`ToDoDlg`の`IDOK`の`COMMAND`メッセージハンドラーが定義されていないためです。 クラスウィザードを使ってそのハンドラーを追加すれば、中の処理は何も実装しなくてもクリア状態は発生しなくなります。 ただし、**Escキー押下でも同様のクリア状態になり、こちらは対応する`IDNO`のメッセージハンドラーを定義しても解消されません。** 参考: ダイアログボックスのキーボードショートカット **Escキー押下でも使える答え:** Enter/Esc各キー押下時のWindowメッセージの発生状況(時系列順)が以下になり、子ダイアログの`WM_WINDOWPOSCHANGING`あたりでクリア状態が発生しているようです。 Enterキー押下時 ``` 子ダイアログ 0x400 DDM_SETFMT 0x111 WM_COMMAND = IDOK 0x046 WM_WINDOWPOSCHANGING 0x047 WM_WINDOWPOSCHANGED 0x000 WM_NULL 0x000 WM_NULL 親ダイアログ 0x014 WM_ERASEBKGND 0x136 WM_CTLCOLORDLG 0x019 WM_CTLCOLOR 0x318 WM_PRINTCLIENT 0x36A WM_KICKIDLE ``` Escキー押下時 ``` 子ダイアログ 0x111 WM_COMMAND = IDNO 0x046 WM_WINDOWPOSCHANGING 0x047 WM_WINDOWPOSCHANGED 0x000 WM_NULL 0x000 WM_NULL 親ダイアログ 0x014 WM_ERASEBKGND 0x136 WM_CTLCOLORDLG 0x318 WM_PRINTCLIENT 0x36A WM_KICKIDLE ``` **最適な方法かどうかは不明ですが、** 親ダイアログの`WM_PRINTCLIENT`のあたりで`OnTcnSelchangeTab()`と同様の処理を行うと、Enter/Escどちらのキー押下でもクリア状態が発生しなくなります。 子ダイアログの`WM_WINDOWPOSCHANGED`以後でも良いのですが、全部の子ダイアログに必要とか、現在アクティブな子ダイアログを判定しなければいけないとか、煩雑になってしまうので。 実装するには、親ダイアログを対象としたクラスウィザードのメッセージタブで、「カスタムメッセージの追加」をクリックし、「カスタムWindowsメッセージ」の欄に「WM_PRINTCLIENT」を入力して「OK」すればソースに追加されるので、その中に`OnTcnSelchangeTab()`の表示処理をコピーすれば出来ます。 例えばタブが2つしかないなら、以下のような簡単な処理で大丈夫です。 ``` if (m_ctrlTab.GetCurSel() == 0) { m_pDlg1->ShowWindow(SW_SHOW); } else { m_pDlg2->ShowWindow(SW_SHOW); } ``` 参考: 第348章 ウィンドウアニメーション この中に`WM_PRINTCLIENT`に関連した説明有り WM_PRINTCLIENT message 上記で解決するのであまり意味はありませんが、**「問題:RedrawWindow関数を使うにしても、InvalidateRect関数を使うにしても、引数のlpcrectに何を設定してよいかわからない。」** に対する答えは以下になります。 特定の領域だけ描画更新したいというので無ければ、いずれも`NULL`を指定しておけば良いのでは? そうすれば、そのウィンドウのクライアント領域全体が対象となるはずです。 (太字は引用者) CWnd::RedrawWindow > > 指定したウィンドウのクライアント領域で、指定した四角形または領域を更新します。 > > > パラメーター > > lpRectUpdate > > 更新用の四角形の座標を格納しているRECT 構造体を指します。 Prgnupdateに有効な地域ハンドルが含まれている場合、このパラメーターは無視されます。 > > prgnUpdate > > 更新リージョンを識別します。 **PrgnupdateとlpRectUpdateの両方が NULL の場合、クライアント領域全体が更新領域に追加されます。** > > > CWnd::InvalidateRect > > `CWnd`更新領域に四角形を追加することによって、指定された四角形内のクライアント領域を無効にします。 > > > パラメーター > > lpRect > > 更新領域に追加する四角形 (クライアント座標) を格納する`CRect`オブジェクトまたはRECT 構造体を指します。 **LpRectが NULL の場合、クライアント領域全体が領域に追加されます。** > > >