65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.49/5 (18投票s)

2008年2月4日

CPOL

3分钟阅读

viewsIcon

77482

downloadIcon

617

如何在不出现闪烁伪影的情况下最小化或最大化 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.
© . All rights reserved.