实例4 非模态对话框
实例目的 在Windows环境中,对话框是一种常用的输入输出手段。对话框有两种类型,非模态和模态。非模态对话框与模态对话框不同,在非模态对话框活动的同时,用户还可以在应用程序的其他地方工作,而模态对话框在其关闭之前,用户不能在同一个应用程序的其他地方工作。本例将从主框架窗口创建一个简单的非模态对话框,在该对话框关闭之前,用户可以在主框架窗口中的其他地方工作,比如选择“打开”文件等。
实现方法 非模态对话框的创建比较复杂。下面介绍具体的方法:
首先,创建一个新的对话框资源,并新建一个类与之关联(用AppWizard); 其次,调用CDialog的默认构造函数来构造对话框对象(注意,创建的不是窗口),这一步在主框架窗口的构造函数中实现。
再次,调用CDialog::Create成员函数创建窗口,Create把资源ID作为参数,并且,在对话框窗口仍然在屏幕上显示时,就立刻返回控件。
最后,在关闭非模态对话框时,注意要调用DestroyWindow函数而不是CloseWindow。删除的只是对话框窗口,对话框对象并未删除,留待创建新的窗口。在程序退出时,再删除该对话框对象。这个过程中对话框与主窗口之间消息的传递必须由用户实现,自定义消息映射(在代码的第10步详细说明)。
在编程过程中必须准确了解何时构造对话框对象,何时创建对话框窗口,何时删除对话框。
程序代码 1. 利用AppWizard生成一个名为ShowModelessDialog的SDI工程,其他步骤均采用VC的默认配置(取消Print And PrintView的选定)。
2. 使用对话框编辑器创建对话框资源。从Insert菜单选择Resource,然后选定Dialog。改变对话框标题为Modeless Dialog。添加一个静态文本控件和一个编辑控件。静态文本控件标题可以任意指定,本例指定为“Password”。
3. 使用ClassWizard创建CModelessDialog类,该类与刚才创建的资源相关联。添加消息处理函数OnCancel和OnOK,代码如下:
void CModelessDialog::OnCancel() { if(m_pView != NULL) { //非模式对话框不调用基类CDialog的OnCancel函数 //发送用户定义的消息WM_GOODBYE m_pView->PostMessage(WM_GOODBYE, IDCANCEL); } else { //模态对话框直接调用基类的OnConcel函数 CDialog::OnCancel(); } }
void CModelessDialog::OnOK() { if(m_pView != NULL) { //非模式对话框不调用基类CDialog的OnOK函数 UpdateData(TRUE); m_pView->PostMessage(WM_GOODBYE, IDOK); } else { //模态对话框直接调用基类的OnOK函数 CDialog::OnOK(); } }
4. 为CModelessDialog类增加如下成员变量和构造函数原型:
private:
CView *m_pView; Public:
CModelessDialog(CView *pView); BOOL Create();
#define WM_GOODBYE WM_USER+5
//指向调用此对话框的视类对象的指针
//保留原有的构造函数,从而可以兼容模态对话框
5. 在CModelessDialog.h中定义WM_GOODBYE消息的ID: 6. 在CModelessDialog.cpp中增加非模态的构造函数和Create函数:
CModelessDialog::CModelessDialog(CView *pView) { //非模态对话框的构造函数,m_pView不为空 m_pView = pView; }
BOOL CModelessDialog::Create() { return CDialog::Create(CModelessDialog::IDD); }
7. 在CShowModelessDialogView.h中添加一个指向非模态对话框的指针: private: CModelessDialog *m_pDlg; 8. 在CShowModelessDialogView.cpp中修改构造函数和析构函数。构造函数在堆上构造对话框对象,并且最终由视图析构函数删除它: CShowModelessDialogView::CShowModelessDialogView() { // TODO: add construction code here //在堆中生成CModelessDialog对象 m_pDlg = new CModelessDialog(this); } CShowModelessDialogView::~CShowModelessDialogView() { //删除对话框对象,释放堆空间 delete m_pDlg; } 9. 在CShowModelessDialogView.cpp中添加代码到虚函数OnDraw中,提示用户按下选择“演示 -> 非模态对话框”来进行演示,并添加头文件的包含语句: #include “ModelessDialog.h” void CShowModelessDialogView::OnDraw(CDC* pDC) { // TODO: add draw code for native data here 106 第4章 时 间控制 }
pDC->TextOut(0, 0, \"请选择 演示 -> 非模态对话框 进行演示\");
10. 为WM_GOODBYE增加自己的消息代码。因为ClassWizard不支持用户定义的消息,所以,我们必须自己编写代码。
在CShowModelessDialogView.cpp中,BEGIN_MESSAGE_MAP语句之后AFX_MSG_MAP括号外增加如下代码,定义消息映射:
ON_MESSAGE(WM_GOODBYE, OnGoodbye);
在CShowModelessDialogView.h中,DECLARE_MESSAGE_MAP语句之前AFX_MSG括号之外,增加如下消息映射的声明:
afx_msg LRESULT OnGoodbye(WPARAM wParam, LPARAM lParam);
同样,在CShowModelessDialogView.cpp中,增加消息处理函数:
LRESULT CShowModelessDialogView::OnGoodbye(WPARAM wParam, LPARAM lParam) { //输出按钮的ID,OK按钮ID为1,CANCLE按钮ID为2 //可以根据此消息进行用户的工作 TRACE(\"CShowModelessDialogView::OnGoodbye %x, %x\\n\ m_pDlg->DestroyWindow(); return 0L; }
11. 使用菜单编辑器添加菜单项“演示—〉非模式对话框”,对应ID为ID_MODELESS。为它创建消息处理函数如下:
void CShowModelessDialogView::OnShowMD() { //如果对话框窗口不存在则创建一个 if(m_pDlg->GetSafeHwnd() == 0) { //创建对话框窗口,显示Show Modeless Dialog对话框 m_pDlg->Create(); } }
编译并运行该程序,选择“演示—〉非模式对话框”,非模态对话框Modeless Dialog跳出,这时,我们仍可以在该对话框中工作,也可以在应用程序的其他地方工作,譬如选择“文件 —〉打开”,就会跳出打开文件对话框。但是打开文件对话框是模态对话框,所以在关闭它之前我们不能在应用程序的其他地方工作了。从中我们也可以体会到非模态对话框与模态对话框的不同。 本例中对非模态对话框传递的消息并未做处理,只是简单的输出了用户所做的选择:确定或取消。如果读者想要根据传递的消息做一些工作,可以自己添加代码实现。
107
因篇幅问题不能全部显示,请点此查看更多更全内容