简体   繁体   English

MFC DoModal 对话框

[英]MFC DoModal Dialog

Okay, so I will admit I have no knowledge of windows API or even MFC.好的,所以我承认我不知道 windows API 甚至 MFC。

I've got an error window popping up when things go hairy (illegal character in a filename string) and I want the error box to be modal.当 go 多毛(文件名字符串中的非法字符)时弹出错误 window 并且我希望错误框是模态的。

For the life of me I can't figure out why it crashes when it hits doModal.对于我的生活,我无法弄清楚为什么它在碰到 doModal 时会崩溃。

Here is the code where I think this can be fixed.这是我认为可以修复的代码。 This code is in the event handler of a button in the main window.此代码位于主 window 中按钮的事件处理程序中。

CDialog *BadFileD = new CDialog();
BadFileD->Create(IDD_STATUS, this); 
BadFileD->DoModal();

Am I just being borderline retarded?我只是边缘性智障吗?

MFC dialog divides two pattern, modal dialog and modeless dialog. MFC 对话框分两种模式,模态对话框和非模态对话框。

(1) Modal dialog usage: (1) 模态对话框用法:

CDialog dlg;
dlg.DoModal();

(2) Modeless dialog usage: (2) 无模式对话用法:

CMyDialog *pDlg = new CMyDialog();
pDlg->Create(ID_DLG, this);
pDlg->ShowWindows(SW_SHOW);

As you can see, we need a new pointer, but do not delete it.如您所见,我们需要一个新指针,但不要删除它。 So, you need to do the following in our CMyDialog class:因此,您需要在我们的CMyDialog class 中执行以下操作:

  1. Add DestroyWindow() method in OnOk() and OnCancel() .OnOk()OnCancel()中添加DestroyWindow()方法。
  2. Add " delete this; " in PostNcDestroy() method.PostNcDestroy()方法中添加“ delete this; ”。

If you do not, your code may cause a memory leak.如果不这样做,您的代码可能会导致 memory 泄漏。 BadFileD is a class member, and you delete it in destructor. BadFileD是 class 成员,您在析构函数中将其删除。 I suggest use Modeless dialog.我建议使用无模式对话框。

For display modal dialog you should use DoModal method only对于显示模式对话框,您应该只使用 DoModal 方法

CDialog *BadFileD = new CDialog(IDD_STATUS, this);
BadFileD->DoModal();

You can read remarks from article您可以阅读文章中的备注

If you desire to just display an error message, it may be that rather than creating your own dialog you can just use AfxMessageBox() .如果您只想显示一条错误消息,那么您可以使用AfxMessageBox()而不是创建自己的对话框。 See Microsoft Developer Network - AfxMessageBox .请参阅Microsoft 开发人员网络 - AfxMessageBox

If you want to do your own dialog box typically with an MFC project you would normally:如果您想使用 MFC 项目来创建自己的对话框,您通常会:

  • create a dialog box template using the resource editor使用资源编辑器创建对话框模板
  • create a class encapsulating the dialog box with the class wizard implementing the behavior desired创建一个 class 封装对话框,使用 class 向导实现所需的行为
  • insert the code to create and display the dialog box into the appropriate place将用于创建和显示对话框的代码插入到适当的位置

However with a simple dialog box that requires no supporting class for complex behavior you can skip the step of creating the encapsulating class with the class wizard and just use CDialog directly.但是,对于一个不需要支持 class 的复杂行为的简单对话框,您可以跳过使用 class 向导创建封装 class 的步骤,直接使用CDialog

One question that needs to be answered is the lifetime of the dialog as well as whether it is to be modal or modeless.需要回答的一个问题是对话的生命周期以及它是模态的还是非模态的。 A modal dialog box requires the user to do something for the application to continue past the modal dialog box.模态对话框需要用户做一些事情,以使应用程序继续通过模态对话框。 A modeless dialog box does not block the application the way a modal dialog box does.无模式对话框不会像模式对话框那样阻塞应用程序。 There is also a system modal dialog box style.还有一种系统模式对话框样式。

Since you say it will be a modal dialog then the lifetime will be short so the entire construction, display, and destruction will probably be in a series of lines of code.既然你说这将是一个模态对话框,那么生命周期就会很短,所以整个构建、显示和销毁可能都在一系列代码行中。 For instance in a CView class with a command handler displaying a modal dialog box you might have:例如,在带有显示模式对话框的命令处理程序的CView class 中,您可能有:

void CViewThing::OnCommandMenuItem ()
{
    CDialog BadFileD(IDD_STATUS);
    int iRetStatus = BadFileD.DoModal();
    // check for status such as IDOK, etc.
    // do whatever is necessary.
}

What the above does is create a dialog box using the dialog resource template IDD_STATUS and displays it as a modal dialog box.上面所做的是使用对话框资源模板IDD_STATUS创建一个对话框并将其显示为模式对话框。 Since it is local object, when the variable BadFileD goes out of scope, the dialog box destructor will be triggered and resources cleaned up for you.由于是本地object,当变量BadFileD走出scope时,会触发对话框析构函数,为你清理资源。

You can also have a modeless dialog box.你也可以有一个无模式的对话框。 In the case of a modeless dialog box you need to consider the variable lifetime because as soon as the variable goes out of scope, the destructor will trigger and the dialog box will disappear.在无模式对话框的情况下,您需要考虑变量的生命周期,因为一旦变量超出 scope,析构函数将触发并且对话框将消失。

So for a modeless dialog box being used with some view class, perhaps providing a tool box of some kind, the CDialog variable will be a member of the CView class which is using it.因此,对于与某些视图 class 一起使用的无模式对话框,可能提供某种工具箱, CDialog变量将是正在使用它的CView class 的成员。 After the modeless dialog box is created, it is displayed or not by using the ShowWindow() member function of the CDialog class (actually a member of the CWnd class from which CDialog is derived).无模式对话框创建后,通过使用CDialog class的ShowWindow()成员function(实际上是CWnd CDialog的成员)的成员来显示或不显示。

void CViewThing::OnCommandMenuItem ()
{
    BadFileD.Create(IDD_STATUS, this);
    BadFileD.ShowWindow(SW_SHOW);   // display the dialog
}

and in the CViewThing class you would have a member variable CDialog BadFileD;CViewThing class 中,您将拥有一个成员变量CDialog BadFileD; . .

Additional considerations其他注意事项

In all of the above examples we are not using pointers so that when the CDialog variable goes out of scope, either from exiting a member function or when the object using the dialog box is destroyed then the dialog box is as well.在上述所有示例中,我们都没有使用指针,因此当CDialog变量退出 scope 时,要么退出成员 function,要么当 object 使用对话框被破坏时。 This object management is done for us.这个 object 管理是为我们完成的。

One thing that you must take into consideration with a modeless dialog box is how to destroy it when you no longer need it.对于无模式对话框,您必须考虑的一件事是当您不再需要它时如何将其销毁。

Since a modal dialog box is usually a short term object, often created as a local variable on the stack, you normally just let it go out of scope to take care of everything dealing with destruction.由于模态对话框通常是一个短期的 object,通常作为堆栈上的局部变量创建,因此您通常只需将 go 放在 scope 之外,以处理所有与破坏有关的事情。

However the lifetime of a modeless dialog box requires that the DestroyWindow() method be used to destroy the dialog box when it is no longer needed.但是,无模式对话框的生命周期要求在不再需要对话框时使用DestroyWindow()方法来销毁对话框。 See Microsoft Developer Network - Destroying the Dialog Box .请参阅Microsoft 开发人员网络 - 销毁对话框

A third usage scenario - embedding a dialog box第三种使用场景——嵌入对话框

There is a third usage of a dialog box that sometimes comes in handy, embedding the dialog box into another window as a control.对话框的第三种用法有时会派上用场,将对话框嵌入另一个 window 作为控件。

In the above examples, the dialog box template specifies the WS_POPUP style for the dialog which is the standard style for a dialog box since the normal way that a dialog box is used is to display as a separate window.在上面的示例中,对话框模板指定了对话框的WS_POPUP样式,这是对话框的标准样式,因为使用对话框的正常方式是显示为单独的 window。

However if you change the WS_POPUP style to WS_CHILD you can then embed the dialog box into another window as a control.但是,如果您将WS_POPUP样式更改为WS_CHILD ,您可以将对话框嵌入到另一个 window 作为控件。 You can remove the other style settings such as WS_SYSMENU , DS_MODALFRAME , and WS_CAPTION and remove the CAPTION line from the dialog template to further change the dialog box.您可以删除其他样式设置,例如WS_SYSMENUDS_MODALFRAMEWS_CAPTION并从对话框模板中删除CAPTION行以进一步更改对话框。 So you will end up with something like:所以你最终会得到类似的东西:

IDD_STATUS DIALOGEX 0, 0, 435, 266
STYLE DS_SETFONT | WS_CHILD
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    LTEXT           "this is some static text to display on this dialog.",IDC_STATIC,81,63,200,32
END

Then just use the resulting dialog box similar to how you would a modeless dialog box with ShowWindow() .然后只需使用生成的对话框,类似于使用ShowWindow()的无模式对话框。

If you need to reposition the embedded dialog box within its container window, you can use the SetWindowPos() method to do so.如果您需要在其容器 window 中重新定位嵌入对话框,您可以使用SetWindowPos()方法来执行此操作。 For instance the following would move the dialog box window within its containing window to be 20 pixels from the left and 10 pixels from the top of the containing window.例如,以下内容会将对话框 window 在其包含的 window 内移动到距包含 window 的左侧 20 个像素和距顶部 10 个像素的位置。

BadFileD.SetWindowPos(NULL, 20, 10, 0, 0, SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM