控制 MFC SDI 应用程序启动状态的简单方法






4.49/5 (18投票s)
如何在不出现闪烁伪影的情况下最小化或最大化 SDI 应用程序。
引言
我最近编写了一个 MFC SDI 应用程序,它会根据命令行参数以普通模式或最小化模式启动。我注意到,当我尝试以最小化模式初始化应用程序时,窗口会在最小化之前短暂地“闪烁”到其正常状态。在搜索后没有找到简单、优雅的解决方案后,我进入了 MFC 代码,看看是否可以找到这个问题的原因(双关语),以及是否可以在我的客户端应用程序中解决这个问题。如果您遇到过类似的问题,请继续阅读。
背景
由 MFC 应用程序向导最初创建的 MFC SDI 程序的初始化和显示由其应用程序类的 InitInstance()
方法处理。乍一看,实际显示初始化窗口的函数似乎是 ShowWindow
调用,它是 InitInstance()
的结尾。应用程序向导生成的文本注释清楚地表明了这一点,这进一步支持了这一前提。见下文
// The one and only window has been initialized, so show and update it. m_pMainWnd->ShowWindow(SW_MINIMIZE); m_pMainWnd->UpdateWindow();
那么,要更改应用程序的启动状态,似乎只需要更改 ShowWindow
中传递的参数。例如,要使应用程序最初以最小化状态显示,可以通过更改以下行来传递参数 SW_MINIMIZE
m_pMainWnd->ShowWindow(SW_SHOW);
to
m_pMainWnd->ShowWindow(SW_MINIMIZE);
在进行此更改并编译并运行程序后,我们将看到应用程序在任务栏中变为最小化之前,会短暂地以正常窗口状态闪烁。 同样,如果我们想最初以最大化状态显示窗口,并且我们修改 ShowWindow
语句以使用 SW_MAXIMIZE
,我们会观察到类似的效果。之所以会发生这种效果,正如我们将在本文后面解释的那样,是因为应用程序向导中的 Microsoft 错误。我们将首先调查此问题的原因,然后提出一个非常简单的解决方案来解决该问题。
为什么会发生闪烁
为了理解为什么应用程序无法正确最小化,我们需要查看构建和显示主窗口的 MFC 代码。通过在 ProcesShellCommand
函数中设置断点,我们看到默认情况下会调用 AppWnd OnFileNew
处理程序。 OnFileNew
调用 CDocument* CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible) OpenDocument
,它创建一个新的文档实例,为该文档创建一个新的框架,最后通过调用 InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
来显示窗口,并显示视图和主框架窗口。当选择与 SW_SHOW
不同的 SW 参数时,应用程序无法正确显示的原因是,InitialUpdateFrame
CFrameWnd::ActivateFrame()
在函数中的窗口初始化期间调用 ShowWindow
。这意味着 InitInstance()
中的 ShowWindow
调用是多余的,不需要的。
解决方案
可以使用两种解决方案来解决闪烁问题。第一个解决方案是创建 SingleDocumentTemplate
的子类,并在最小化的情况下使用 bMakeVisible = false
调用我们派生的 OpenDocument
版本。但是,这并不能解决使用 SW_MAXMIMIZE
的情况。另一种解决方案更简单,可以用于任何 ShowWIndow
模式,是在初始化窗口之前设置应用程序的 ShowWindow
属性,如下所示
CSingleDocTemplate * pDocTemplate; pDocTemplate = new CSingleDocTemplate ( IDR_MAINFRAME, RUNTIME_CLASS(CMyMFCProgramDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CMyMFCProgramView)); AddDocTemplate(pDocTemplate); // Parse command line for standard shell commands, DDE, file open CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // Add the following line: // Set the initial window display to whatever mode you like this->m_nCmdShow = SW_MAXIMIZE; // Dispatch commands specified on the command line if (!ProcessShellCommand(cmdInfo)) return FALSE; // The following line should be deleted since it is not needed // for a SDI application that used MFC The one and only window has // been initialized, so show and update it. //m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow(); return TRUE;
有人可能会问,InitInstance
中的 ShowWindow()
行没有作用,那么 Microsoft 为什么首先将该行放在那里。答案是,如果有人决定使用 MFC 应用程序向导构建一个 SDI 应用程序,并选中不使用 MFC 的选项,则需要此行来显示窗口。但是,如果使用 MFC,Microsoft 应该删除此行。但是,由于绝大多数应用程序最初使用带有 SW_SHOW
参数的 ShowWindow
来显示,因此调用两次 ShowWindow
(第一次在 ActivateFrame
中,如上所述)不会影响应用程序的显示。
历史
- First version.