非模态对话框(Modeless Dialog),又称为无模式对话框,是一种允许用户在打开对话框的同时继续操作其他窗口的对话框类型。与模态对话框不同,非模态对话框不会阻止用户与其他窗口的交互。
基本信息
非模态对话框允许用户在处理非模态对话框的同时处理目标对话框。其不会垄断用户的输入,如图所示。
Windows应用程序中,对话框分为两种。另一种是模态对话框。二者的区别在于当对话框打开时,是否允许用户进行其他对象的操作。
要建立非模态对话框需要调用两个函数Create()和
ShowWindow()
创建和关闭
无模式对话框与有
模式对话框不同的是在创建后其他窗口都可以继续接收用户输入,因此无模式对话框有些类似一个弹出窗口。创建无模式对话框需要调用
BOOL CDialog::Create( UINT nIDTemplate, CWnd* pParentWnd = NULL );之后还需要调用
BOOL CDialog::
ShowWindow( SW_SHOW);进行显示,否则
无模式对话框将是不可见的。相关代码如下:
void CYourView::OnOpenDlg(
void)
{
/*假设IDD_TEST_DLG为已经定义的对话框资源的ID号*/
CTestDlg *dlg=new CTestDlg;
dlg->Create(IDD_TEST_DLG,NULL);
dlg->ShowWindow(SW_SHOW);
/*不要调用 delete dlg;*/
}
在上面的代码中我们新生成了一个对话框对象,而且在退出函数时并没有销毁该对象。因为如果此时销毁该对象(对象被销毁时窗口同时被销毁),而此时对话框还在显示就会出现错误。那么这就提出了一个问题:什么时候销毁该对象。我时常使用的方法有两个:
在对话框退出时销毁自己:在对话框中
重载OnOK与
OnCancel在函数中调用父类的同名函数,然后调用
DestroyWindow()强制销毁窗口,在对话框中映射
WM_DESTROY消息,在消息处理函数中调用delete this;强行删除自身对象。相关代码如下:
void CTestDlg1::OnOK()
{
CDialog::OnOK();
DestroyWindow();
}
void CTestDlg1::OnCancel()
{
DestroyWindow();
}
void CTestDlg1::OnDestroy()
{
CDialog::OnDestroy();
delete this;
}
这种方法的要点是在窗口被销毁的时候,删除自身对象。所以你可以在任何时候调用
DestroyWindow()以达到彻底销毁自身对象的作用。(DestroyWindow()的调用会引起OnDestroy()的调用)
通过向父亲窗口发送消息,要求其他窗口对其进行销毁:首先需要定义一个消息用于进行通知,然后在对话框中映射
WM_DESTROY消息,在消息处理函数中调用消息发送函数通知其他窗口。在接收消息的窗口中利用
ON_MESSAGE映射处理消息的函数,并在消息处理函数中删除对话框对象。相关代码如下:
/*更改对话框的有关文件*/
CTestDlg2::CTestDlg2(
CWnd* pParent /*=NULL*/)
: CDialog(CTestDlg2::IDD, pParent)
{/*m_pParent为一
成员变量,用于保存通知窗口的
指针,所以该指针不能是一个临时指针*/
ASSERT(pParent);
m_pParent=pParent;
//{{AFX_DATA_INIT(CTestDlg2)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void CTestDlg2::OnOK()
{
CDialog::OnOK();
DestroyWindow();
}
void CTestDlg2::
OnCancel()
{
CDialog::OnCancel();
DestroyWindow();
}
void CTestDlg2::OnDestroy()
{
CDialog::OnDestroy();
/*向其他窗口发送消息,将自身
指针作为一个参数发送*/
m_pParent->
PostMessage(WM_DELETE_DLG,(
WPARAM)this);
}
/*在消息接收窗口中添加消息映射*/
/*在头文件中添加函数定义*/
afx_msg LONG OnDelDlgMsg(WPARAM wP,LPARAM lP);
/*添加消息映射代码*/
ON_MESSAGE(WM_DELETE_DLG,OnDelDlgMsg)
END_MESSAGE_MAP()
/*实现消息处理函数*/
LONG CMy53_s1View::OnDelDlgMsg(WPARAM wP,LPARAM lP)
{
delete (CTestDlg2*)wP;
return 0;
}
/*创建对话框*/
void CMy53_s1View::OnTest2()
{
CTestDlg2 *dlg=new CTestDlg2(this);
dlg->Create(IDD_TEST_DLG_2);
dlg->
ShowWindow(SW_SHOW);
}
在这种方法中我们利用消息来进行通知,在Window系统中利用消息进行通知和传递数据的用法是很多的。
同样
无模式对话框的另一个作用还可以用来在用户在对话框中的输入改变时可以及时的反映到其他窗口。下面的代码演示了在对话框中输入一段文字,然后将其更新到视图的显示区域中,这同样也是利用了消息进行通知和数据传递。
/*在对话框中取出数据,并向其他窗口发送消息和数据,将数据
指针作为一个参数发送*/
void CTestDlg2::OnCommBtn()
{
char szOut[30];
GetDlgItemText(IDC_OUT,szOut,30);
m_pParent->SendMessage(WM_DLG_NOTIFY,(
WPARAM)szOut);
}
/*在消息接收窗口中*/
/*映射消息处理函数*/
ON_MESSAGE(WM_DLG_NOTIFY,OnDlgNotifyMsg)
/*在视图中绘制出字符串 m_szOut*/
void CMy53_s1View::
OnDraw(CDC* pDC)
{
CMy53_s1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
pDC->TextOut(0,20,m_szOut);
}
/*处理通知消息,保存信息并更新显示*/
LONG CMy53_s1View::OnDlgNotifyMsg(WPARAM wP,LPARAM lP)
{
m_szOut=(char*)wP;
Invalidate();
return 0;
}
此外这种用法利用消息传递数据的方法对有
模式对话框和其他的窗口间通信也一样有效