使用非模态对话框的小技巧
作者:刘胤
工作上有用到非模态对话框,但是使用上有如下麻烦,
所有者拥有一个非模态对话框指针,非模态对话框在关闭的时候要设置这个指针为空,这样一来,非模态对话框就必须"知道"所有者并且实现
了这样的非模态对话框,就不能让它在栈上创建(因为是 delete this),也不能一次创建多个非模态对话框(当然,这种情况很少)。如果把非
模态对话框声明为 CNonModalDialg m_dlg;,那用户点击 OK 的时候,你就得 ShowWindow(SW_HIDE),这和对话框的本意还是有点不一致。
class CNonModalDialg;
class COwner
{
private:
CNonModalDialg *m_pDlg;
};
class CNonModalDialg
{
...
void OnOK()
{
...
delete this;
}
void OnCancel()
{
...
delete this;
}
void OnDestory()
{
m_pOwner->m_pDlg = NULL;
}
private:
COwner *m_pOwner;
};
通过 C++ 的模板,实现了一个 NonModal 类可以解决以上问题。代码如下。
#ifndef NonModal_H
#define NonModal_H
template <typename DialogImpl, typename OwnerType>
class NonModal : public DialogImpl
{
public:
NonModal(OwnerType *pOwner)
: m_pOwner(pOwner)
{
}
void SetOwner(OwnerType *pOwner) { m_pOwner = pOwner; }
virtual BOOL DestroyWindow()
{
DialogImpl::DestroyWindow();
return DestroySelf();
}
protected:
virtual void OnOK()
{
DialogImpl::OnOK();
DestroySelf();
}
virtual void OnCancel()
{
DialogImpl::OnCancel();
DestroySelf();
}
private:
virtual ~NonModal() {}
BOOL DestroySelf()
{
BOOL bRet = FALSE;
if (m_pOwner) {
m_pOwner->OnDestroyNonModal(this);
}
bRet = DialogImpl::DestroyWindow();
delete this;
return bRet;
}
OwnerType *m_pOwner;
};
#define DECLARE_NonModalDialog(DialogImpl, OwnerImpl, VariableName) /
private:/
typedef NonModal<DialogImpl, OwnerImpl> DialogImpl##NonModal; /
friend DialogImpl##NonModal; /
/
DialogImpl##NonModal *VariableName; /
void OnDestroyNonModal(DialogImpl##NonModal *pDlg) /
{ /
if (pDlg == VariableName) { /
VariableName = NULL; /
} /
}
#endif
使用方法如下:
class COwnerDlg
{
...
DECLARE_NonModalDialog(CAboutDlg, COwnerDlg, m_pNonModalAboutDlg)
};
void COwnerDlg::ShowNonModal()
{
if (m_pNonModalAboutDlg == NULL) { // 记得初始化 m_pNonModalAboutDlg = NULL;
m_pNonModalAboutDlg = new CAboutDlgNonModal(this);
m_pNonModalAboutDlg->Create(CAboutDlg::IDD);
}
m_pNonModalAboutDlg->ShowWindow(SW_SHOW);
m_pNonModalAboutDlg->UpdateWindow();
}
void CCOwnerDlg::OnDestroy()
{
CDialog::OnDestroy();
if (m_pNonModalAboutDlg) {
m_pNonModalAboutDlg->DestroyWindow();
}
m_pNonModalAboutDlg = NULL;
}
这样对话框要成为非模态对话框就加在所有者里面加上 DECLARE_NonModalDialog,如果不用非模态对话框,也不用修改对话框的代码了。