關於CMDIChildWnd和InitInstance的作用機理

小小小魚兒啊發表於2018-05-21

InitIstance中,程式進行

CMainFrame* pMainFrame = new CMainFrame;

if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;

m_pMainWnd = pMainFrame;

進行對框架,視類視窗,文件的建立,在建立過程中:

對視類的建立:在Create建立時會執行視類的OnCreate函式,所以我們可以在OnCreate函式裡面修改檢視視窗,返回到Create併成功建立後,程式接著會執行OnInitialUpdate函式,這個函式用來對視類進行初始化。然後進行UpdateWindow函式傳送WM_PAINT訊息引起訊息響應函式OnPaint函式的執行,在OnPaint函式中,呼叫了OnDraw函式,所以我們可以在OnDraw函式中對檢視進行改變。且每次重繪視窗都會傳送WM_PAINT訊息,然後對其進行響應。

對話方塊建立:對話方塊同樣進行Create之後,執行OnCreate函式,此時,函式的控制元件還並沒有建立,所以不能再這個函式裡對控制元件進行修改,建立成功後執行了OnInitDialog函式,這個函式可以對對話方塊內部控制元件等進行初始化。

對CMainFrame的框架建立:視窗在設計註冊之後,執行Create和CreateEx,在執行CreateEX時,傳送訊息WM_CREATE,這時,CMainFrame類的OnCreate函式進行響應:


int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;

if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1;      // fail to create
}


if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
 sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1;      // fail to create

}

在OnCreate函式裡,可以看到,函式繼續呼叫了基類CFrameWnd的OnCreate函式,然後呼叫了工具欄的建立函式,OnCreate函式呼叫結束之後返回到CreateEx函式,在CreateEx函式中,若查詢我們可以發現,其呼叫了PreCreateWindow函式,這個函式為視窗的型別再改變函式,之後CreateEx結束,至此,視窗建立完成,但還並沒有顯示,所以,回到InitInstance函式執行ShowWindow和UpdataWindow進行視窗的顯示和更新,在次,我們做個試驗:

CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;


// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;


cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;                //此句表示不建立預設文件的視窗和檢視!!!!!!


ParseCommandLine(cmdInfo);


// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;


// pMainFrame->MessageBox("hello");                                       當訊息盒子程式碼在這裡時,視窗還未顯示之前就會出現


// The main window has been initialized, so show and update it.
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();


// pMainFrame->MessageBox("hello");                                        當訊息盒子程式碼在這裡是,視窗顯示之後會出現


pMainFrame->FrameWndInit();                                      //所以,當框架建立完畢時,這個自定義函式才會執行


return TRUE;

註釋中已經解釋明確,當我們將MessageBox放在ShowWindow之前時,訊息盒子會在視窗出現之前出現,當我們將其放在之後時,訊息盒子會在視窗出現之後出現,所以,當我們想在視窗建立的時候就改變視窗時,可以在CMainFrame的OnCreate和PreCreateWindow函式中進行實現,而當我們想在視窗建立之後改變視窗時,就可以在InitInstance的顯示視窗和更新視窗之後加入程式碼進行視窗改變,如上例return之前我的那句加入了自定義函式的程式碼。我的自定義函式是一個為主框架新增3個子視窗函式,因為我建立的是一個單文件多程式的MFC框架,而且我取消了預設視窗的建立,所以在建立框架完成並顯示之後,只會出現CMainFrame的框架,並不會出現視類視窗,而我之後要做的就是在主框架建立完成之後在其客戶區新增3個子視窗並顯示出來。我的FrameWndInit函式程式碼如下:

void CMainFrame::FrameWndInit()

{  

CRect rect;  

       CRect m_3Drect; 

        CRect m_Initrect;
CRect m_TimShowrect;

GetClientRect(&rect);

m_3Drect.right=rect.right/2;
m_3DViewWnd = new C3DViewWnd();
m_3DViewWnd->Create(NULL,"3DViewWnd",WS_CHILD|WS_BORDER|WS_VISIBLE/* |WS_OVERLAPPEDWINDOW */,m_3Drect,NULL,NULL);
    
m_Initrect.left=rect.right/2;
m_Initrect.right=rect.right;
m_Initrect.bottom=rect.bottom/2;
m_InitWnd = new CInitWnd();
    m_InitWnd->Create(NULL,"InitWnd",WS_CHILD|WS_BORDER|WS_VISIBLE/* |WS_OVERLAPPEDWINDOW */,m_Initrect,NULL,NULL);


m_TimShowrect.top=rect.bottom/2;
m_TimShowrect.left=rect.right/2;
m_TimShowrect.right=rect.right;
m_TimShowrect.bottom=rect.bottom;
m_TimeShowWnd = new CTimeShowWnd();
    m_TimeShowWnd->Create(NULL,"TimeShowWnd",WS_CHILD|WS_BORDER|WS_VISIBLE/* |WS_OVERLAPPEDWINDOW */,m_TimShowrect,NULL,NULL);

}

這個函式是初始化了我的3個建立好的CMDIChildWnd的子類。其3個類的物件指標定義程式碼如下:

CTimeShowWnd* m_TimeShowWnd;
CInitWnd* m_InitWnd;

C3DViewWnd* m_3DViewWnd;

至此,子視窗建立完成,執行之後發現如期所想。


本人QQ:401190754,如果感覺文章有什麼問題,歡迎討論。




相關文章