MFC修改对话框类基类为自定义对话框类(VS2019)

需求

在MFC中,有时候可能需要创建派生自自定义对话框类的对话框类(这句话很复杂,慢慢理解),也就是说创建了一个自定义对话框A,再创建一个自定义对话框B,如果B用到了A的很多方法,就需要让B派生自A。但是,给对话框添加类时,基类选项里并没有A类,只有默认的CDialogEx等类。下面,我们就来探讨一下手动把B类设置为A类的派生类的方法。
假如,我们要模仿Word中的查找和替换功能,有两个类,一个是查找对话框类,类名为CFindTextDialog,一个是替换对话框类,类名是CReplaceDialog。因为替换对话框有很多功能和查找对话框一样,所以应该让CReplaceDialog成为CFindTextDialog类的派生类。步骤如下:

创建CFindTextDialog类

先创建CFindTextDialog的资源和对话框类。创建对话框类时基类要选CDialogEx。如图所示:
创建CFindTextDialog类
CFindTextDialog.h:

#pragma once


// CFindTextDialog 对话框

class CFindTextDialog : public CDialogEx
{
    
    
	DECLARE_DYNAMIC(CFindTextDialog)

public:
	CFindTextDialog(CRichEditCtrl& RichEdit, CWnd* pParent = nullptr);   // 标准构造函数
	virtual ~CFindTextDialog();
// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum {
    
     IDD = IDD_FINDDIALOG };
#endif

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
	FINDTEXTEXW m_ft;
	CRichEditCtrl& m_RichEdit;
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnBnClickedFindNext();
	virtual void PostNcDestroy();
	afx_msg void OnBnClickedCasesensitive();
};

CFindTextDialog.cpp:

// CFindTextDialog.cpp: 实现文件
//

#include "pch.h"
#include "Word.h"
#include "CFindTextDialog.h"
#include "afxdialogex.h"


// CFindTextDialog 对话框

IMPLEMENT_DYNAMIC(CFindTextDialog, CDialogEx)

CFindTextDialog::CFindTextDialog(CRichEditCtrl& RichEdit,
	CWnd* pParent)
	: CDialogEx(IDD_FINDTEXTDIALOG, pParent), m_RichEdit(RichEdit)
{
    
    
}

CFindTextDialog::~CFindTextDialog()
{
    
    
}

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


BEGIN_MESSAGE_MAP(CFindTextDialog, CDialogEx)
	ON_BN_CLICKED(IDC_FINDNEXT, &CFindTextDialog::OnBnClickedFindNext)
	ON_BN_CLICKED(IDC_CASESENSITIVE, &CFindTextDialog::OnBnClickedCasesensitive)
END_MESSAGE_MAP()


// CFindTextDialog 消息处理程序


void CFindTextDialog::OnBnClickedFindNext()
{
    
    
	m_RichEdit.GetSel(m_ft.chrg);
	m_ft.chrg.cpMax = -1;
	CString strText;
	GetDlgItem(IDC_TEXTTOFIND)->GetWindowTextW(strText);
	m_ft.lpstrText = strText;
	if (m_RichEdit.GetSelText() == strText)
		m_ft.chrg.cpMin += 1;
	if (((CButton*)GetDlgItem(IDC_CASESENSITIVE))->
		GetCheck())
		m_RichEdit.FindTextW(FR_DOWN | FR_MATCHCASE, &m_ft);
	else
		m_RichEdit.FindTextW(FR_DOWN, &m_ft);
	if (m_ft.chrgText.cpMax != -1)
		m_RichEdit.SetSel(m_ft.chrgText);
	else
		MessageBoxW(L"未找到指定文本!", L"查找", MB_ICONINFORMATION | MB_OK);
	m_RichEdit.SetFocus();
}

void CFindTextDialog::PostNcDestroy()
{
    
    
	CDialogEx::PostNcDestroy();
	delete this;
}


void CFindTextDialog::OnBnClickedCasesensitive()
{
    
    
	m_RichEdit.SetFocus();
}


创建CReplaceDialog类

创建CReplaceDialog的资源。添加对话框类时,基类没有CFindTextDialog选项,所以我们先选CDialogEx。具体步骤省略。

修改代码

首先,要把CReplaceDialog.h中添加#include"CFindTextDialog.h",并把class CReplaceDialog : public CDialogEx改为class CReplaceDialog : public CFindTextDialog
然后,将CReplaceDialog.cpp中的IMPLEMENT_DYNAMIC(CReplaceDialog, CDialogEx)改为IMPLEMENT_DYNAMIC(CReplaceDialog, CFindTextDialog)BEGIN_MESSAGE_MAP(CReplaceDialog, CDialogEx)改为BEGIN_MESSAGE_MAP(CReplaceDialog, CFindTextDialog)
然后,我们发现自动生成的构造函数有问题,CDialogEx(IDD_REPLACEDIALOG,pParent)提示“不允许使用间接非虚拟基类”,解决办法是用CFindTextDialog的构造函数,但是那样创建出来的对话框也是CFindTextDialog的资源,所以我们必须修改CFindTextDialog类的构造函数,添加一个默认参数ID。
CFindTextDialog修改后的构造函数:

//声明
CFindTextDialog(CRichEditCtrl& RichEdit, CWnd* pParent = nullptr, UINT ID = IDD_FINDDIALOG);
//定义
CFindTextDialog::CFindTextDialog(CRichEditCtrl& RichEdit,
	CWnd* pParent, UINT ID)
	: CDialogEx(ID, pParent), m_RichEdit(RichEdit)
{
    
    
}

接下来,把CReplaceDialog的构造函数改成这样:

CReplaceDialog::CReplaceDialog(CRichEditCtrl& RichEdit, CWnd* pParent /*=nullptr*/)
	: CFindTextDialog(RichEdit, pParent, IDD_REPLACEDIALOG)
{
    
    

}

这样,CReplaceDialog就可以直接调用CFindTextDialog的函数了。

添加消息处理程序

虽然我们手动设置了派生类,但CReplaceDialog执行时对应控件事件还没有处理。如果控件是新添加的,我们就可以直接使用添加事件处理程序的方法,但如果是CFindTextDialog里就有的,我们就需要做一下处理了。有以下两种方法:

1. 直接使用代码(不推荐)

可以直接在CReplaceDialog的MESSAGE_MAP中添加代码。如,按钮按下对应代码是:

ON_BN_CLICKED(IDC_FINDNEXT, &CReplaceDialog::OnBnClickedFindNext)
//这里的OnBnClickedFindNext是派生过来的CFindTextDialog中的函数

但这样有一大缺陷,就是如果有些复杂的消息,我们不知道对应的宏,就没法手动添加了。所以,我们需要更方便的方法。

2.修改自动添加的代码(推荐)

我们可以直接用平常添加消息处理程序的方法,VS会自动创建消息映射,我们直接把自动生成的函数声明和定义删掉,调用基类的函数就行了。

猜你喜欢

转载自blog.csdn.net/qq_54121864/article/details/115572147
今日推荐