MFCテクノロジーシリーズ(四)--Frameウィンドウ(2)


前編に続き、「Frameウィンドウ(1)」
3. MDI
これはMFCが提供するもう一つの複雑なDoc-Viewフレームワークである.CDocument,CViewの派生クラスとCMDIChildWnd(winmdi.cpp)の派生クラス(Frame Window)からなるFrameウィンドウで、これらのクラスのRUNTIMECLASSマクロ情報はCMultiDocTemplateクラス(docmulti.cpp)によって管理され、CDocManagerクラスにも登録されている.SDIと同様に,これらのランタイムクラス情報も前述した一対のマクロによって管理される.
MFCはまた、これらの子Frameウィンドウを収容する親Frameウィンドウベースクラス:CMDIFrameWndクラス(winmdi.cpp)を提供する.MDIアプリケーションの場合、そのTop-levelウィンドウはクラスの派生クラスです.
MDIがViewを作成する手順は、次のとおりです.
1.Newメニュー項目(起動時にデフォルトで開く)をクリックした場合、AppクラスからCDocManagerにアクセスするOnFileNewメソッド.このメソッドでは、登録されているDocumentタイプが1つだけではない場合、CNewType Delgがポップアップされ、Documentが選択されます.そして次のステップに進みます.デフォルトの動作を書き換える場合は、ベースクラスCWinAppの応答メソッドを呼び出すのではなく、OnFileNewの応答ロジックを自分で作成できます.
2.MDIである以上、CMultiDocTemplateのOpenDocumentFileダミーメソッドを実行します.SDIと同様に、このメソッドも作成プロセスの核心メソッドです.実は、DocTemplateから見ると、この中の基本的な過程はSDIとほぼ同じです.すなわち、CreateNewDocumentを呼び出してDocumentを作成し、CreateNewFrameを呼び出してサブFrameウィンドウを作成し、空のドキュメントを作成する場合はDocumentクラスのOnNewDocumentダミーメソッドを呼び出し、既存のドキュメントを開く場合はOnOpenDocumentダミーメソッドを呼び出す.CreateNewFrameでは、CreateViewメソッドを呼び出して対応するViewウィンドウを作成します.
3.CreateNewFrameメソッドでは、LoadFrameマウントサブFrameウィンドウが呼び出されます.このとき、2つの重要なメンバー、すなわちm_hMenuSharedとm_hAccelTableは,それぞれサブFrameウィンドウのメニューとアクセラレータキーテーブルである.これらは対応するMultiDocTemplateインスタンスから得られる(doc template構造の最初のパラメータはFrameリソースIDである).なお、MFCフレームでは、コードを減らすことができるように、FrameウィンドウのTitleアイコン、メニュー、アクセラレータキーのリソースIDをともに同一値として規定している(これらのリソースのタイプ(RT値)が異なる以上、互いに上書きされる心配はない)
4.最後に、InitUpdateFrameを呼び出します.詳細については、SDIセクションを参照してください.
 
MFCの上記2つのMDIウィンドウクラスはいずれもWM_MDIシリーズメッセージのカプセル化.以下の点に特に注意する必要があります.
1.CMDIChildWndの親ウィンドウは、MDIクライアントと呼ばれるウィンドウである.すべてのサブフレームウィンドウを閉じると、空白の領域にあるのがウィンドウです.このウィンドウの親ウィンドウがCMDIFrameWndウィンドウです
2.サブフレームウィンドウに関するメッセージは、このMDIクライアントウィンドウに送信されます.実はchild frameウィンドウとmain frameウィンドウの間の絆です.main frameウィンドウのm_を直接通過できますhWndMDIClient共有メンバーこのウィンドウのハンドルを取得
3.DocTemplateに基づいて、異なるドキュメントテンプレートを登録することで、実際には異なるchild frameウィンドウで収容されている同じdocumentの異なるviewを簡単に作成できます.自分のコードにchild frameウィンドウを作成する場合は、上記の手順の主な方法を参照してください.
 
MDIの各主要シーンにおいて、メッセージシーケンス:
1.child frameを作成する
<00001> 000301DC 
     
      S WM_MDICREATE
      lpmdic:
     
      0012F
     
     
      18C
     
     
<00002> 000301DC R WM_MDICREATE hwndChild:
     
      000F
     0546
     
<00003> 000301DC 
     
      S WM_MDISETMENU
      hmenuFrame:000504E7 hmenuWindow:000804B5
     
<00004> 000301DC R WM_MDISETMENU hmenuFrameOld:000704DF
     
<00005> 000301DC 
     
      S WM_MDIREFRESHMENU
     
     
<00006> 000301DC R WM_MDIREFRESHMENU hmenuFrame:000504E7
     

2.child frameを閉じる
<00001> 000301DC 
     
      S WM_MDIDESTROY
      hwndChild:
     
      000F
     0546
     
<00002> 000301DC 
     
      S WM_MDISETMENU
      hmenuFrame:000704DF hmenuWindow:00000000
     
<00003> 000301DC R WM_MDISETMENU hmenuFrameOld:000504E7
     
<00004> 000301DC 
     
      S WM_MDIREFRESHMENU
     
     
<00005> 000301DC R WM_MDIREFRESHMENU hmenuFrame:000704DF
     
<00006> 000301DC R WM_MDIDESTROY
     

3.サブフレームウィンドウの配置
積層:WM_MDICASCADE
タイル:WM_MDITILE
整列アイコン:WM_MDIICONARRANGE
4.メニューから後ろのサブフレームウィンドウを選択すると、現在のサブフレームウィンドウが別のサブフレームウィンドウに切り替わる(spy結果から、マウスを直接使用してサブフレームを選択した場合、WM_MDIACTIVATEメッセージは生成されない)
<00001> 000301DC 
     
      S WM_MDIACTIVATE
      hwndChildActivate:0036067E
     
<00002> 000301DC 
     
      S WM_MDIREFRESHMENU
     
     
<00003> 000301DC R WM_MDIREFRESHMENU hmenuFrame:000504E7
     
<00004> 000301DC 
     
      S WM_MDISETMENU
      hmenuFrame:000504E7 hmenuWindow:000804B5
     
<00005> 000301DC R WM_MDISETMENU hmenuFrameOld:000504E7
     
<00006> 000301DC R WM_MDIACTIVATE
     

5.サブフレームウィンドウのシステムメニューから「次」を選択
<00001> 000301DC 
     
      S WM_MDINEXT
      hwndChild:0036067E fNext:False
     
<00002> 000301DC 
     
      S WM_MDIREFRESHMENU
     
     
<00003> 000301DC R WM_MDIREFRESHMENU hmenuFrame:000504E7
     
<00004> 000301DC 
     
      S WM_MDISETMENU
      hmenuFrame:000504E7 hmenuWindow:000804B5
     
<00005> 000301DC R WM_MDISETMENU hmenuFrameOld:000504E7
     
<00006> 000301DC R WM_MDINEXT
     

6.サブフレームウィンドウを最小化(?)
7.サブフレームウィンドウが最大化される(WM_MDIMAXIMIZE)(ただしspy++を使用してメッセージはキャプチャされない)
8.サブframeウィンドウが最小化または最大化された状態から回復する(WM_MDIRESTORE)(ただしspy++を使用してメッセージがキャプチャされていない)
 
メニュー状態にかかわる動作のほとんどが,メニューの切り替えであることがわかる.