【问题标题】:Creating a new base CDialogEx derived class创建一个新的基础 CDialogEx 派生类
【发布时间】:2018-06-19 10:01:08
【问题描述】:

我有很多CDialogEx 派生类在OnInitDialog 中执行类似的操作:

CMeetingScheduleAssistantApp::InitialiseResizeIcon(m_bmpResize, m_lblResize, this);
CMeetingScheduleAssistantApp::RestoreWindowPosition(_T("PublisherDB"), this, true);

然后,我在每个派生对话框类中添加了以下内容:

int CPublishersDatabaseDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CDialogEx::OnCreate(lpCreateStruct) == -1)
        return -1;

    // Save Initial window size to m_rcInit
    GetWindowRect(&m_rcInit);

    return 0;
}

void CPublishersDatabaseDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
    // Set the minimum window size to initial size.
    lpMMI->ptMinTrackSize.x = m_rcInit.Width();
    lpMMI->ptMinTrackSize.y = m_rcInit.Height();

    CDialogEx::OnGetMinMaxInfo(lpMMI);
}

void CPublishersDatabaseDlg::OnClose()
{
    CMeetingScheduleAssistantApp::SaveWindowPosition(_T("PublisherDB"), this);
    CDialogEx::OnClose();
}

每个对话框唯一不同的是用于保存窗口位置的短语。

我想要一个基于CDialogEx 的类,我可以从中继承它来执行上述操作。我看过 SO,似乎有一些问题,并创建了一个 CDialog 类并从另一个 CDialog 类继承。但是我想创建的这个类更通用。有效地用作基础而不是CDialogEx

这可以吗?我是否过于复杂了?

问题

为什么我尝试创建一个新类,派生自CDialogEx

我不知道是不是因为它需要一个 对话框 ID,如 here 所述。

CDialogCFormViewCPropertyPage 等类,需要对话框 ID

所以我无法找到正确的方法来创建用于我所有其他对话框类的基本 CDialogEx 类。

更新

我创建了这段代码,它告诉我CResizingDialog 不是类或命名空间:

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

IMPLEMENT_DYNAMIC(CResizingDialog, CDialogEx)

CResizingDialog::CResizingDialog(const CString& strWindowID, UINT nIDTemplate, CWnd* pParent = nullptr)
    : m_strWindowID(strWindowID), CDialogEx(nIDTemplate, pParent)
{

}

CResizingDialog::~CResizingDialog()
{
}

void CResizingDialog::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CResizingDialog, CDialogEx)
    ON_WM_CREATE()
    ON_WM_GETMINMAXINFO()
    ON_WM_CLOSE()
END_MESSAGE_MAP()


int CResizingDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CDialogEx::OnCreate(lpCreateStruct) == -1)
        return -1;

    // Save Initial window size to m_rcInit
    GetWindowRect(&m_rcInit);

    return 0;
}


void CResizingDialog::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
    // Set the minimum window size to initial size.
    lpMMI->ptMinTrackSize.x = m_rcInit.Width();
    lpMMI->ptMinTrackSize.y = m_rcInit.Height();

    CDialogEx::OnGetMinMaxInfo(lpMMI);
}


void CResizingDialog::OnClose()
{
    SaveWindowPosition(m_strWindowID, this);

    CDialogEx::OnClose();
}

【问题讨论】:

  • 您想专门化您的对话框基类。 C++ 继承是该问题的标准解决方案。只需创建从CDialogEx 派生的对话框基类,提供与CDialogEx' 相同的参数的c'tor 加上您的字符串标识符。将const CString& 成员添加到该基础,并从您的 c'tor 初始化列表中对其进行初始化,就像基础一样。本质上类似于CDialogBase::CDialogBase(const CString& phrase, UINT nIDTemplate, CWnd* pParent=NULL) : m_phrase(phrase), CDialogEx(nIDTemplate, pParent) {}
  • 只需从头开始创建您的CDialogEx 专业化,无需使用(经常损坏的)向导。无论如何,这对学习体验更好。
  • 您需要在使用它的所有其他文件中#include "ResizingDialog.h"
  • 这就是预编译头文件的工作方式。 #include <stdafx.h> 指令之前的所有内容都将被忽略,这就是您收到错误的原因,即符号不是类。如果您想防止此类错误,您可以使用/FI (Name Forced Include File) 编译器选项,而不再考虑您的预编译头文件。好吧,直到事情再次出错。
  • 我不知道编译器选项的确切格式,但您可以使用 Visual Studio 的项目设置对话框(C/C++ -> 高级 -> 强制包含文件)来启用它(并检查命令行,以防您有兴趣)。我相信您可以启用每个项目以及每个编译单元的选项。无论如何,我几乎从不使用它。唯一的例外是当我必须编译无法修改但仍想继续使用预编译头文件的第 3 方代码时。

标签: c++ inheritance mfc cdialog


【解决方案1】:

基于鼓励我尝试手动创建类的 cmets,我让它工作了:

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

IMPLEMENT_DYNAMIC(CResizingDialog, CDialogEx)

CResizingDialog::CResizingDialog(const CString& strWindowID, UINT nIDTemplate, CWnd* pParent /* nullptr */, bool bOnlyStorePosition /* false */)
    : m_strWindowID(strWindowID),
      m_bOnlyStorePosition(bOnlyStorePosition), CDialogEx(nIDTemplate, pParent)
{

}

CResizingDialog::~CResizingDialog()
{
}

void CResizingDialog::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CResizingDialog, CDialogEx)
    ON_WM_CREATE()
    ON_WM_GETMINMAXINFO()
    ON_WM_CLOSE()
END_MESSAGE_MAP()

int CResizingDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CDialogEx::OnCreate(lpCreateStruct) == -1)
        return -1;

    // Save Initial window size to m_rcInit
    GetWindowRect(&m_rcInit);

    return 0;
}

void CResizingDialog::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
    // Set the minimum window size to initial size.
    lpMMI->ptMinTrackSize.x = m_rcInit.Width();
    lpMMI->ptMinTrackSize.y = m_rcInit.Height();

    CDialogEx::OnGetMinMaxInfo(lpMMI);
}

void CResizingDialog::OnClose()
{
    SaveWindowPosition(m_strWindowID, this);

    CDialogEx::OnClose();
}

void CResizingDialog::OnOK()
{
    SaveWindowPosition();
    CDialogEx::OnOK();
}

BOOL CResizingDialog::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    if(!m_bOnlyStorePosition)
        InitialiseResizeIcon(m_bmpResize, m_lblResize, this);

    RestoreWindowPosition(m_strWindowID, this, true);

    return TRUE;  // return TRUE unless you set the focus to a control
                  // EXCEPTION: OCX Property Pages should return FALSE
}

我决定将 app 类中的方法复制到这个新的对话框类中。最终它们可以从应用程序类中删除。我唯一还要做的就是#include我的资源文件,因为图像需要知道资源 ID 的值。

这是ResizingDialog.h 标头:

#pragma once
#include <afxwin.h>

class CResizingDialog : public CDialogEx
{
    DECLARE_DYNAMIC(CResizingDialog)

public:
    CResizingDialog(const CString& phrase, UINT nIDTemplate, CWnd* pParent = nullptr, bool bOnlyStorePosition = false); // Constructor
    virtual ~CResizingDialog(); // Destructor

protected:
    void OnOK() override;
    virtual void DoDataExchange(CDataExchange* pDX) override;    // DDX/DDV support
    void SaveWindowPosition(void) { SaveWindowPosition(m_strWindowID, this); }

public:
    BOOL OnInitDialog() override;
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
    afx_msg void OnClose();
    DECLARE_MESSAGE_MAP()

private:
    CBitmap m_bmpResize;
    CStatic m_lblResize;
    CRect m_rcInit;
    CString m_strWindowID;
    bool m_bOnlyStorePosition;

    void RestoreWindowPosition(CString strWindow, CWnd* pWindow, bool bOverrideState = false);
    void SaveWindowPosition(CString strWindow, CWnd* pWindow);
    void InitialiseResizeIcon(CBitmap& rBmpResize, CStatic& rLblResize, CWnd* pDialog);
};

SaveWindowPositionRestoreWindowPositionInitialiseResizeIcon 的实际函数未在此处显示,因为它们与问题没有直接关系。

【讨论】:

  • 你还应该包含头文件。
  • "ResizingDialog.h"。阅读此答案以了解如何从 CDialogEx 继承的人肯定需要此信息。
  • 我的意思是在答案中包含“ResizingDialog.h”的内容,而不是#include 行。
  • 我刚刚刷新了页面,不是。 .h 和 .cpp 文件中的声明必须交换。
  • 您询问了OnGetMinMaxInfoOnInitDialog 的关系。它在OnInitDialog 之前被调用一次。每当您调整大小时都会再次调用它,到那时 m_rcInit 已设置并按预期工作。
猜你喜欢
  • 2018-05-22
  • 2017-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-26
  • 2015-08-10
  • 2014-09-29
  • 1970-01-01
相关资源
最近更新 更多