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);


多文档程序也不会闪烁,对话框程序没测试,应该也可以。

网上搜了很多方法都不能避免闪烁,不知还有没有其它方法可行,也许我这个不是最好的方法。分享出来大家做个参考。


展开阅读全文

没有更多推荐了,返回首页