原文:http://www.cnblogs.com/WeedQian/archive/2009/12/28/1634484.html
简介
非模式对话框常常感到困惑的新手程序员。基本上是一个非模式对话框是一个使我们能够互动,与其他的Windows ,甚至当非模式对话框仍然是在屏幕上。如果您请记住,几个漂亮的小动作,然后编程非模式对话框,将非常简单。
创建非模式对话框
简单的方法创建一个非模式对话框是使用Create()
。通过名称的对话框中的模板资源和一个可选的CWnd*
这点,向父窗口。如果您不通过一个父窗口指针的主要应用程序窗口将被作为父窗口。 Create()
将返回true
如果调用是成功的。
自Create()
立即传回,不像DoModal()
, you must never declare your modeless dialog as a local variable与范围及寿命只有功能函数的地方,这是申明。而不是分配非模式对话框就堆。如果你不这样做,非模式对话框会被销毁时刻,你退出功能函数,使你申明它。
另一种解决办法是要申明您的非模式对话框作为一个堆的成员对象你的主要框架窗口或您的CWinApp
派生类。一的优势,用此方法是,你实际上有控件权的非模式对话框,由于你有一个指针。
由的方式不同,非模式对话框,非模式对话框需要有WS_VISIBLE
风格设置如果你不想让他们看见后,立即进行创作。否则,你就会有明确要求ShowWindow()
与SW_SHOW
。事实上,我建议您这样做,而不是去所有的地方,改变默认的风格。
CModeLess *m_pmodeless = new CModeLess(this); m_pmodeless->Create(CModeLess::IDD); m_pmodeless->ShowWindow(SW_SHOW);
父问题
惯常的做法是使父窗口的主窗口对您的应用程序,这是典型的主框架窗口。现在的一个问题是与这是因为非模式对话框,将继续留在上方的这父窗口。它可以让您的互动与主框架窗口,或许它还包含一个CView
得出的视图。但它可能是恼人的和不可取的有非模式对话框留在顶端。该解决方案在这里是创建非模式对话框作为一个子的桌面上。使用GetDesktopWindow()
得到一个指针到桌面上,并通过表示,由于父窗口为非模式对话框,在您的调用Create()
。
m_pmodeless->Create(CModeLess::IDD,GetDesktopWindow());
销毁非模式对话框
既然我们已分配内存就堆,我们必须将它删除时,非模式对话框是摧毁,否则我们很快会遇到很大的麻烦与内存泄漏,左,右和中心。当对话框是摧毁了最后一则留言,我们收到处理类是WM_NCDESTROY
消息。该OnNcDestroy
功能函数是引用,这在原来调用虚拟函数PostNcDestroy
。这正是我们可以delete
我们的非模式对话框。 First Call调查的基类的功能函数,以便它是否自己的清理。
void CModeLess::PostNcDestroy() { CDialog::PostNcDestroy(); delete this; }
问题与成员对象
如果非模式对话框是一个成员对象的父窗口的类,我们有一个轻微的问题在这里。成员变量仍持有指针引用,但它引用的记忆已被删除。有替代这个问题。一种方法是后一用户定义的消息给父窗口和处理它在父类,通过设置非模式对话框成员变量,以NULL
。另一种方法是使用GetParent()
得到父窗口,如有的话,然后在它的实际父类。现在我们已进入到父类的成员变量保存指针向非模式对话框。设置为NULL
。后者的方法是描绘后来我讨论如何限制非模式对话框,以一个实例。前者的方法是,如下所示: -
void CModeLess::PostNcDestroy() { CDialog::PostNcDestroy(); GetParent()->PostMessage(WM_MODELESS_CLOSED,0,0); delete this; } LRESULT CMainFrame::OnMyMethod(WPARAM wParam, LPARAM lParam) { m_pmodeless = NULL; return 0; }
问题OnOK ( )和OnCancel ( )
在模态对话框,每个人都包括女王的厨师,有OK/cancel按钮。我认为,想必在许多其他更了解市民的意见,您要做好,以避免OK和取消对一非模式对话框。但如果因为某种不可避免的原因,您最希望能有他们对您的非模式对话框,那么您将需要超过预约两种功能函数。
这里是我的非模式版本的OnCancel()
功能函数。正如你可以看到,我只是调用的DestroyWindow()
和我没有困扰,调用基类。事实上, don't call the base class at all 。基类函数将拜会EndDialog()
这与DoModal()
。
void CModeLess::OnCancel() { DestroyWindow(); }
好吧,现在我的非模式版本的OnOK()
。我有调用的DestroyWindow()
作为,在OnCancel()
,但也有一些额外的代码,也正如你所看到的。我调用UpdateData
,因为这是什么OnOK()
是否在一个模态对话框。如果DDV宏是成功的验证,然后UpdateData(true)
返回我们摧毁的窗口,否则DDV消息框是自动显示给用户和我们拒绝销毁对话框。因此,我们是模拟的行为,一模态对话框的OK按钮在这里。
void CModeLess::OnOK() { if(UpdateData(true)) { DestroyWindow(); } }
传递回数据
在模态对话框,我们仍然可以使用数据变量时, DoModal()
返回,因为对话框的对象并没有被摧毁,但只有基这个的对话框窗口已被摧毁。这是也有可能与非模式对话框,用漂亮的技巧,如下所示。
void CModeLess::OnOK() { if(UpdateData(true)) { ((CMainFrame*)m_parent)->m_x=m_sss; DestroyWindow(); } }
在这里,我已经指派的值对话框的数据变量m_sss
到父类的成员变量, m_x
。在这里, m_parent
是一个指针,向父窗口。此处您想知道我得到这个m_parent
从,滚动起来,看看如何我已构造的,我非模式对话框对象。我会重复,单行刷新您的内存,也帮助您避免滚动,从而节省您的一些能源。
CModeLess *m_pmodeless = new CModeLess(this);
你可以看到,我已通过this
向构造。在我而言,这是一个指针,以我的CFrameWnd
派生类,其中应用程序向导已命名为CMainFrame
我。现在看看我的CModeLess
类的构造。
CModeLess::CModeLess(CWnd* pParent /*=NULL*/) : CDialog(CModeLess::IDD, pParent) { //{{AFX_DATA_INIT(CModeLess) m_sss = 0; //}}AFX_DATA_INIT m_parent=pParent; //This is where I point m_parent to my main frame window }
这一切,慢慢是有道理的,嗯?
跟踪非模式对话框计数
让我们说你要只有一个实例,该非模式对话框活在同一时间。在这种情况下,每一次用户启动一些行动,结果,在使该非模式对话框,你必须检查,看看是否该非模式对话框是已经在运作中。也就是说, m_pmodeless
是非模式对话框的成员,你的类类。在类的构造一套m_pmodeless
,以NULL
。现在您每一次检查,看看是否m_pmodeless
是NULL
,如果这是NULL
,创建一个新的非模式对话框,否则,显示MessageBox
认为,对话框是已经活跃或使用SetForegroundWindow()
把非模式对话框到前景..
这里是我如何创建我的非模式对话框现在我想限制他们只是一个在时间: -
if(m_pmodeless) { m_pmodeless->SetForegroundWindow(); } else { m_pmodeless = new CModeLess(this); m_pmodeless->Create(CModeLess::IDD); m_pmodeless->ShowWindow(SW_SHOW); }
但是,当对话框被摧毁,我们必须告知父类指针,它现在是无用的。我们做什么,是集指针NULL
,在PostNcDestroy
。事实上,这是十分重要的,你这样做,否则下一次用户试图启动非模式对话框,您的程序会崩溃,因为它认为m_pmodeless
仍然是指向一个有效的对话框窗口,并试图调用 SetForegroundWindow()
它。这里是我PostNcDestroy
: -
void CModeLess::PostNcDestroy() { CDialog::PostNcDestroy(); ((CMainFrame*)m_parent)->m_pmodeless = NULL; delete this; }