在MFC框架中,使用对话框是一项非常普遍的任务。在大量的代码中,有时候可能需要根据某些条件动态地创建对话框。此时,使用IMPLEMENT_DYNCREATE宏来设计动态创建的对话框是一种很好的方式。
在本文中,我们将从简化代码开始,逐渐深入探讨如何使用IMPLEMENT_DYNCREATE宏来实现封装性和重用性。我们将首先学习如何使用IMPLEMENT_DYNCREATE宏来简化代码,之后我们将学习如何创建自己的动态创建对话框类,并探讨如何将其封装成一个可重用的类。
一、简化代码
首先,我们将学习如何使用IMPLEMENT_DYNCREATE宏来简化代码。如果您不知道什么是动态创建,请先看一下下面的代码。
1. 子对话框类声明
class CSubDlg : public CDialogEx
{
DECLARE_DYNAMIC(CSubDlg)
public:
CSubDlg(CWnd* pParent = nullptr);
virtual ~CSubDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_SUBDLG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
public:
CString m_strSubName;
};
2. 子对话框类实现
IMPLEMENT_DYNAMIC(CSubDlg, CDialogEx)
CSubDlg::CSubDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_SUBDLG, pParent)
, m_strSubName(_T(""))
{
}
CSubDlg::~CSubDlg()
{
}
void CSubDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_NAME, m_strSubName);
}
BEGIN_MESSAGE_MAP(CSubDlg, CDialogEx)
END_MESSAGE_MAP()
BOOL CSubDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
return TRUE;
}
然后,我们可以在其他对话框或框架窗口中使用以下代码来创建对话框。
CSubDlg *pDlg = new CSubDlg;
pDlg->Create(CSubDlg::IDD);
pDlg->ShowWindow(SW_SHOW);
当我们这样使用动态创建时,我们需要在析构函数中delete该对话框。我们不能忘记这个步骤,因为这是我们分配的新存储器。如果忘记释放,将导致内存泄漏。
pDlg->DestroyWindow();
delete pDlg;
在大型项目中,可能会重复多次这种代码。这将大大增加代码的长度和复杂度。幸运的是,IMPLEMENT_DYNCREATE可以帮助我们简化代码。代码如下所示。
CSubDlg *pDlg = new CSubDlg;
pDlg->Create(CSubDlg::IDD);
pDlg->ShowWindow(SW_SHOW);
使用IMPLEMENT_DYNCREATE宏将上面的代码简化成以下两行:
CSubDlg *pDlg = new CSubDlg;
pDlg->DoModal();
此时,我们将使用IMPLEMENT_DYNCREATE宏来自动生成大量代码。
二、创建自己的动态创建对话框类
现在,我们将学习如何创建我们自己的动态创建对话框类。可以通过以下步骤轻松完成此操作。
1、创建新的对话框类
以下代码是一个示例:
class CMyDlg : public CDialogEx
{
DECLARE_DYNAMIC(CMyDlg)
public:
CMyDlg(CWnd* pParent = nullptr);
virtual ~CMyDlg();
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_MYDLG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX);
DECLARE_MESSAGE_MAP()
protected:
virtual BOOL OnInitDialog();
public:
afx_msg void OnBnClickedButtonOk();
afx_msg void OnBnClickedButtonCancel();
public:
CString m_strName;
};
注意:IMPLEMENT_DYNCREATE必须在CMyDlg声明上面。比如:
class CMyDlg : public CDialogEx
{
DECLARE_DYNAMIC(CMyDlg)
IMPLEMENT_DYNCREATE(CMyDlg)
public:
CMyDlg(CWnd* pParent = nullptr);
virtual ~CMyDlg();
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_MYDLG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX);
DECLARE_MESSAGE_MAP()
protected:
virtual BOOL OnInitDialog();
public:
afx_msg void OnBnClickedButtonOk();
afx_msg void OnBnClickedButtonCancel();
public:
CString m_strName;
};
2、在CMyDlg的cpp文件中实现这个类
以下是一些有用的CMyDlg类的实现。
IMPLEMENT_DYNAMIC(CMyDlg, CDialogEx)
CMyDlg::CMyDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_MYDLG, pParent)
, m_strName(_T(""))
{
}
CMyDlg::~CMyDlg()
{
}
void CMyDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_NAME, m_strName);
}
BEGIN_MESSAGE_MAP(CMyDlg, CDialogEx)
ON_BN_CLICKED(IDOK, &CMyDlg::OnBnClickedButtonOk)
ON_BN_CLICKED(IDCANCEL, &CMyDlg::OnBnClickedButtonCancel)
END_MESSAGE_MAP()
BOOL CMyDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
return TRUE;
}
void CMyDlg::OnBnClickedButtonOk()
{
UpdateData(TRUE);
EndDialog(IDOK);
}
void CMyDlg::OnBnClickedButtonCancel()
{
EndDialog(IDCANCEL);
}
3、调用CMyDlg
以下是一个简单的示例。
CMyDlg *pDlg;
pDlg = new CMyDlg; // 创建对话框
if (pDlg->DoModal() == IDOK) // 显示对话框
{
CString strName = pDlg->m_strName;
// 如果按下了 OK 按钮,则在此处执行操作
}
pDlg->DestroyWindow();
delete pDlg;
注意:当我们使用动态创建对话框时,必须在定义的地方使用delete操作,否则会导致内存泄漏。
三、实现封装性和重用性
现在,我们将进一步学习如何将我们的动态创建对话框类封装成一个可重用的类。以下是我们如何实现封装性和重用性:
1、重写CDialogEx
我们可以通过重写CDialogEx类中的一些方法,来使我们的类更具有封装性和重用性。以下是我们需要重写的方法:
CMyDlg()
virtual ~CMyDlg()
virtual BOOL Create(UINT nIDTemplate, CWnd* pParentWnd = NULL)
virtual INT_PTR DoModal()
virtual void PostNcDestroy()
以下是CMyDlg类,已经改写了这些方法:
class CMyDlg : public CDialogEx
{
DECLARE_DYNAMIC(CMyDlg)
public:
CMyDlg(CWnd* pParent = nullptr);
virtual ~CMyDlg();
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_MYDLG };
#endif
protected:
DECLARE_MESSAGE_MAP()
protected:
virtual BOOL OnInitDialog();
virtual void PostNcDestroy();
virtual void DoDataExchange(CDataExchange* pDX);
virtual INT_PTR DoModal();
protected:
virtual BOOL Create(UINT nIDTemplate, CWnd* pParentWnd = NULL);
public:
afx_msg void OnBnClickedButtonOk();
afx_msg void OnBnClickedButtonCancel();
public:
CString m_strName;
};
2、重写CDialogEx类中的方法
我们可以使用以下代码来重写CDialogEx类中的方法。
CMyDlg::CMyDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_MYDLG, pParent)
, m_strName(_T(""))
{
}
CMyDlg::~CMyDlg()
{
}
BOOL CMyDlg::Create(UINT nIDTemplate, CWnd* pParentWnd /*= nullptr*/)
{
BOOL bRet = CDialogEx::Create(nIDTemplate, pParentWnd);
CenterWindow();
return bRet;
}
void CMyDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_NAME, m_strName);
}
INT_PTR CMyDlg::DoModal()
{
INT_PTR nRet = CDialogEx::DoModal();
if (nRet == IDOK)
{
// TODO: 如果按下确定按钮
}
return nRet;
}
BOOL CMyDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
return TRUE;
}
void CMyDlg::OnBnClickedButtonOk()
{
OnOK();
}
void CMyDlg::OnBnClickedButtonCancel()
{
OnCancel();
}
void CMyDlg::PostNcDestroy()
{
CDialogEx::PostNcDestroy();
delete this;
}
3、使用我们的类
现在,我们可以用以下简洁的代码使用我们的类:
CMyDlg *pDlg = new CMyDlg;
if (pDlg->DoModal() == IDOK)
{
// 如果单击了确定按钮
CString strName = pDlg->m_strName;
}
pDlg->DestroyWindow();
delete pDlg;
在使用封装类的时候,我们已经隐藏了我们使用的具体实现细节。例如,我们无需调用delete this;语句,因为它已在PostNcDestroy()函数中实现。
四、总结
在本文中,我们详细介绍了如何使用IMPLEMENT_DYNCREATE宏来设计动态创建对话框,并通过实例编写了如何将实现封装性和重用性。现在,您已经准备好在您的项目中使用这种技术了。