1. 程式人生 > >MFC隱藏視窗時解決視窗閃爍問題

MFC隱藏視窗時解決視窗閃爍問題

先說一下解決方法(以單文件程式為例)

1,從CSingleDocTemplate派生自己的類CMySingleDocTemplate並重寫InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc, BOOL bMakeVisible /* = TRUE */);這個虛方法,在此方法體中設定bMakeVisible=false;並給所有子視窗傳送一個WM_INITIALUPDATE的訊息,如下面;(我用的vs2008通過類嚮導無法增加基類為CSingleDocTemplate的類,需要自己手動新增)

void CMySingleDocTemplate::InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc, BOOL bMakeVisible /* = TRUE */)
{
bMakeVisible = FALSE;
AfxGetMainWnd()->SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
return CSingleDocTemplate::InitialUpdateFrame(pFrame, pDoc, bMakeVisible);
}

2,在App類 的InitInstance方法中把CSingleDocTemplate改成自己的派生類CMySingleDocTemplate如下:(別忘了包含自己派生類的標頭檔案)

CMySingleDocTemplate* pDocTemplate;
pDocTemplate = new CMySingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CSimuCommServerDoc),
RUNTIME_CLASS(CMainFrame),       // 主 SDI 框架視窗
RUNTIME_CLASS(CSimuCommServerView));

3,在ParseCommandLine(cmdInfo);的前面寫一句m_bLoadWindowPlacement = FALSE;並把m_pMainWnd->ShowWindow(SW_SHOW);中的SW_SHOW->SW_HIDE

再說一下原理:

通過除錯追蹤發現在m_pMainWnd->ShowWindow(SW_SHOW);這一句之前還有兩處地方都會顯示視窗,然後再隱藏所以會出現閃爍問題,只要把兩處顯示視窗的地方不讓其顯示即不會閃爍。

第一次在CWinAppEx::LoadState方法中的

if (m_bLoadWindowPlacement)
{
//--------------------------------------------------------
// Set frame default(restored) size:
//--------------------------------------------------------
ReloadWindowPlacement(pFrameImpl->m_pFrame);
}

這一部分,執行ReloadWindowPlacement(pFrameImpl->m_pFrame);就會顯示視窗,因此可以把m_bLoadWindowPlacement這個變數設定為FALSE避免第一次顯示。因為m_bLoadWindowPlacement是CWinAppEx的成員變數且App從CWinAppEx派生,因此在App類中直接用這個變數並把他改成FALSE即可。

ReloadWindowPlacement方法中的

if (pFrameWnd->GetWindowPlacement(&wp))
{
wp.rcNormalPosition = rectNormal;
wp.showCmd = nShowCmd;


RECT rectDesktop;
SystemParametersInfo(SPI_GETWORKAREA,0, (PVOID)&rectDesktop,0);
OffsetRect(&wp.rcNormalPosition, -rectDesktop.left, -rectDesktop.top);


pFrameWnd->SetWindowPlacement(&wp);


bRet = TRUE;
}

nShowCmd為true因此視窗會顯示。

第二次在

void CDocTemplate::InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc,
BOOL bMakeVisible)
{
// just delagate to implementation in CFrameWnd
pFrame->InitialUpdateFrame(pDoc, bMakeVisible);
}

pFrame->InitialUpdateFrame(pDoc, bMakeVisible);會第二次顯示視窗,由於InitialUpdateFrame為虛擬函式,因此可以從CDocTemplate派生子類並重寫這個虛方法把bMakeVisible設為false避免第二次閃爍。但是僅僅這樣會有一個小問題,就是InitialUpdateFrame(pDoc, bMakeVisible)這個方法體裡面如果bMakeVisible為true還會給子視窗傳送訊息通知子視窗或子控制元件初始化,否則顯示視窗時會出現子視窗不正常顯示的問題,因為把bMakeVisible設定為FALSE了不會給子視窗傳送訊息了,因此自己增加一句給子視窗傳送訊息的方法即AfxGetMainWnd()->SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);

多文件程式也不會閃爍,對話方塊程式沒測試,應該也可以。

網上搜了很多方法都不能避免閃爍,不知還有沒有其它方法可行,也許我這個不是最好的方法。分享出來大家做個參考。