VC窗口啓動隱藏時閃爍問題解決方法(原創)
最近由於項目需要,做了一個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,於是就有了文章開頭我說的修改方法。