MFC視窗啟動隱藏時閃爍問題解決方法
最近由於專案需要,做了一個VC托盤程式,讓該程式在後臺執行,當程式啟動時我需要將視窗隱藏,但總是在隱藏前會閃爍一下再隱藏,於是我跟蹤程式碼到MFC類庫裡終於發現問題給解決了。
下面都是針對建立的單文件程式而講的,因為我建立的是單文件工程,其它的型別工程我沒試過,多文件工程應該也可以用下面的方法,好了,開始講解了。
如果你使用VC6做的單文件程式,那麼只需在BOOL CXXXXApp::InitInstance()方法中新增如下程式碼:
m_nCmdShow = SW_HIDE;
if (!ProcessShellCommand(cmdInfo))
return FALSE;
即在"if (!ProcessShellCommand(cmdInfo))”在這一句的上方加一句程式碼"m_nCmdShow = SW_HIDE;"即可
如果使用VC2008建立的單文件程式,那麼需要在BOOL CXXXXApp::InitInstance()方法中新增如下程式碼:
m_nCmdShow = SW_HIDE;
m_bLoadWindowPlacement=FALSE;
if (!ProcessShellCommand(cmdInfo))
return FALSE;
即在"if (!ProcessShellCommand(cmdInfo))”在這一句的上方加兩行程式碼"m_nCmdShow = SW_HIDE;"和"m_bLoadWindowPlacement=FALSE;"
大家可能覺得奇怪,為什麼不一樣呢?
原因是在VC2008建立的單文件程式中,CXXXXApp預設繼承的CWinAppEx類,該類中新添加了一些處理。如果你在"if (!ProcessShellCommand(cmdInfo))”處打上斷點按F11,走到一個方法後繼續按F11跟蹤進去直到程式碼走到下面這個方法:
BOOL CWinAppEx::LoadState(LPCTSTR lpszSectionName /*=NULL*/, CFrameImpl* pFrameImpl /*= NULL*/)
而在該方法中有下面一段程式碼,問題就出在這裡:
if (m_bLoadWindowPlacement)
{
//--------------------------------------------------------
// Set frame default(restored) size:
//--------------------------------------------------------
ReloadWindowPlacement(pFrameImpl->m_pFrame);
}
我們再繼續跟進BOOL CWinAppEx::ReloadWindowPlacement(CFrameWnd* pFrameWnd),其實現程式碼如下:
BOOL CWinAppEx::ReloadWindowPlacement(CFrameWnd* pFrameWnd)
{
ASSERT_VALID(pFrameWnd);
CCommandLineInfo cmdInfo;
AfxGetApp()->ParseCommandLine(cmdInfo);
if (cmdInfo.m_bRunEmbedded || cmdInfo.m_bRunAutomated)
{
//Don't show the main window if Application
//was run with /Embedding or /Automation.
return FALSE;
}
CRect rectNormal;
int nFlags = 0;
int nShowCmd = SW_SHOWNORMAL;
BOOL bRet = FALSE;
if (LoadWindowPlacement(rectNormal, nFlags, nShowCmd))
{
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
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;
}
}
if (pFrameWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWndEx)))
{
CDockingManager *pDockingManager = ((CMDIFrameWndEx *)pFrameWnd)->GetDockingManager();
pDockingManager->ShowDelayShowMiniFrames(TRUE);
}
else if (pFrameWnd->IsKindOf(RUNTIME_CLASS(CFrameWndEx)))
{
CDockingManager *pDockingManager = ((CFrameWndEx *)pFrameWnd)->GetDockingManager();
pDockingManager->ShowDelayShowMiniFrames(TRUE);
}
return bRet;
}
看我加了下劃線加粗的程式碼行,發現我之前設定的"m_nCmdShow = SW_HIDE;"在這裡被更改,所以會閃爍,那麼看到這裡問題就可以解決了。
我們發現之所以會進ReloadWindowPlacement方法,是因為m_bLoadWindowPlacement=TRUE的原因,這個值在CWinAppEx的建構函式中初始化為TRUE了,那麼我們就應該想辦法將m_bLoadWindowPlacement置為FALSE,所以我們使用VC2008開發時就應該在呼叫ReloadWindowPlacement方法前把m_bLoadWindowPlacement置為FALSE,於是就有了文章開頭我說的修改方法。