除非隐藏 CFrameWnd,否则文件对话框不会刷新

File Dialog does not get refreshed unless CFrameWnd is hidden

我正在更新一些不能在 Win7 或更高版本上运行的旧软件。因此,我正在重建一些使用最新 win32 更新的 MFC 库。

现在我有两个问题:

  1. MessageBox 出现在 CFrameWnd 后面,因此无法访问它并发送应用程序停止。
  2. 打开对话框(无论是基于 CFileDialog 还是 IFileDilog)在更改文件类型时不会刷新。

但是,如果隐藏CFrameWnd,这两个问题都可以解决。或者,对于 MessageBox,如果您编写:PostMessage(0x118),则无需隐藏 window;其实我也不知道为什么。

这里一定有我遗漏的东西。

我在使用继承自 IFileDialog 的 OpenFileDialog class 时还有另一个问题。是在没有选择文件的情况下关闭此对话框时,应用程序崩溃。

//--targetver.h
        #pragma once
        #include <sdkddkver.h>

//--stdafx.h:
        #ifndef CS_EXTRALEAN
        #define CS_EXTRALEAN
        #endif
        #pragma once
        #include "targetver.h"
        #include<afxwin.h>
        #include<afxext.h>
        #include<afxcmn.h>

//--stdafx.cpp
        #include "stdafx.h"

//--CMainWnd.h
        #pragma once

        class CMainWnd : public CFrameWnd
        {
        public:
            CMainWnd();
            ~CMainWnd();

            afx_msg void OnPaint();
            afx_msg void OnLButtonDown(UINT, CPoint);

            DECLARE_MESSAGE_MAP()
        };

//--CMainWnd.cpp
    #include "stdafx.h"
    #include"CMainWnd.h"

    BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)
        ON_WM_PAINT()
        ON_WM_LBUTTONDOWN()
    END_MESSAGE_MAP()

    CMainWnd::CMainWnd()
        : CFrameWnd()
    {
        CString class_name = AfxRegisterWndClass(
            CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,
            AfxGetApp()->LoadStandardCursor(IDC_ARROW),
            (HBRUSH)::GetStockObject(BLACK_BRUSH),
            AfxGetApp()->LoadStandardIcon(IDI_ASTERISK));

        HRESULT hResult = this->Create(
            class_name,
            L"This is CMainWnd",
            WS_OVERLAPPEDWINDOW,
            this->rectDefault,
            NULL,
            NULL,
            0,
            NULL);
    }

    CMainWnd::~CMainWnd() { }

    void CMainWnd::OnPaint()
    { }

    void CMainWnd::OnLButtonDown(UINT, CPoint)
    {
        MessageBox(L"HELLO MFC", L"MFC", MB_OK);
    }

//--CAppWnd.h
#pragma once

class CAppWnd : public CWinApp
{
public:
    CAppWnd();
    ~CAppWnd();

    BOOL InitInstance();

    DECLARE_MESSAGE_MAP()
};

//--CAppWnd.cpp
#include "stdafx.h"
#include "CAppWnd.h"
#include "CMainWnd.h"

BEGIN_MESSAGE_MAP(CAppWnd, CWinApp)
END_MESSAGE_MAP()

CAppWnd::CAppWnd()
    :CWinApp()
{ }

CAppWnd::~CAppWnd()
{ }

BOOL CAppWnd::InitInstance()
{
    this->m_pMainWnd = new CMainWnd;
    this->m_pMainWnd->ShowWindow(m_nCmdShow);

    return CWinApp::InitInstance();
}

CAppWnd The_App;

有一个简单的问题。您覆盖 OnPaint 但没有调用默认过程。 OnPaint 处理 WM_PAINT 消息,它不会原谅这个错误。

void CMainWnd::OnPaint()
{ 
    CFrameWnd::OnPaint(); //<= this was missing

    //custom paint...
    //CClientDC dc(this);
    //dc.TextOut(0, 0, L"test");
    //dc is automatically released...
}

或者您可以使用 CPaintDC,它是 BeginPaint/EndPaint API

的包装器
void CMainWnd::OnPaint()
{ 
    CPaintDC dc(this);

    //custom paint...
    //dc.TextOut(0, 0, L"test");
    //dc is automatically released...
}

如果您不在此帧中进行任何绘画 window 则删除整个 CMainWnd::OnPaint() 函数和相应的 ON_WM_PAINT 消息。

以上更改应该可以解决您的错误。我会重写其余代码,以便它首先调用默认覆盖。示例:

#include "stdafx.h"
#include "resource.h"

class CMainWnd : public CFrameWnd
{
public:
    CMainWnd();
    ~CMainWnd();
    afx_msg void OnPaint();
    afx_msg void OnLButtonDown(UINT, CPoint);
    DECLARE_MESSAGE_MAP()
};

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)
    ON_WM_PAINT()
    ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()

CMainWnd::CMainWnd() : CFrameWnd() {}
CMainWnd::~CMainWnd() {}

void CMainWnd::OnPaint()
{ 
    CFrameWnd::OnPaint();
}

void CMainWnd::OnLButtonDown(UINT f, CPoint pt)
{
    CFrameWnd::OnLButtonDown(f, pt);
    CFileDialog dlg(TRUE, 0, 0, 0, 
        L"All files|*.*|" 
        L"Text files|*.txt;*.txt||" , this);
    if (dlg.DoModal() == IDOK)
        MessageBox(dlg.GetPathName(), L"MFC", MB_OK);
}

class CAppWnd : public CWinApp
{
public:
    BOOL InitInstance();
};

BOOL CAppWnd::InitInstance()
{
    CWinApp::InitInstance();
    CMainWnd *frame = new CMainWnd;
    CString class_name = AfxRegisterWndClass(
        CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,
        AfxGetApp()->LoadStandardCursor(IDC_ARROW),
        (HBRUSH)::GetStockObject(BLACK_BRUSH),
        AfxGetApp()->LoadStandardIcon(IDI_ASTERISK));

    frame->Create(class_name, L"This is CMainWnd", 
        WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL, NULL, 0, NULL);
    frame->ShowWindow(m_nCmdShow);
    m_pMainWnd = frame;
    return TRUE;
}

CAppWnd The_App;

请注意,您可以直接调用静态成员,例如CFrameWnd::rectDefault,这两种方式都不会导致错误,但它使代码更清晰。