一个 MFC 应用程序中的两个对话框
Posted
技术标签:
【中文标题】一个 MFC 应用程序中的两个对话框【英文标题】:Two dialogs in one MFC application 【发布时间】:2013-04-13 09:35:05 【问题描述】:我正在尝试制作一个基于对话框的 MFC 应用程序,其中两个对话框需要按顺序显示。
这意味着,一旦第一个对话框(模态)显示并关闭(按确定),就需要调出第二个对话框。我的要求是第二个对话框应该是无模式的。
但我观察到的是显示了第二个对话框,但没有调用任何消息处理函数来响应用户消息。我认为消息映射本身不起作用,而被覆盖的函数(如 OnInitdialog)正在被调用.我尝试用模态对话框替换这个无模式对话框,唉,doModal() 本身失败了。 这是小代码:
CFirstDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
// TODO: Place code here to handle when the dialog is
// dismissed with OK
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
CSecondDlg *dlgModeLess = new CSecondDlg();
dlgModeLess->Create(CSecondDlg::IDD,NULL);
m_pMainWnd = dlgModeLess;
dlgModeLess->ShowWindow(SW_SHOW);
dlgModeLess->UpdateWindow();
这是第二个对话框的消息映射:
BEGIN_MESSAGE_MAP(CSecondDlg, CDialog)
ON_MESSAGE(TRAY_MESSAGE,OnTrayMessage)
ON_BN_CLICKED(IDOK, &CSecongDlg::OnBnClickedOk)
ON_BN_CLICKED(IDC_RADIO1, &CSecondDlg::OnBnClickedRadio1)
END_MESSAGE_MAP()
我认为我在做一些概念上的错误。请分享您对解决这种情况需要做些什么的想法。
【问题讨论】:
你为什么不带上另一个模态对话框?当除了该对话框之外没有其他窗口时,对话框是模态的还是非模态的并不重要。 【参考方案1】:正如我在上一篇文章中提到的,第二个对话框没有必要是非模态的。
只要做这样的事情:
BOOL CMyTestApp::InitInstance()
CMyTestDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
COtherDlg Dlg ;
m_pMainWnd = &dlg;
if (Dlg.DoModal() == IDCANCEL)
...
else if (nResponse == IDCANCEL)
...
return FALSE;
【讨论】:
您是否尝试运行该程序?由于我不知道的原因,当我在我的环境中运行该程序时。你的回答会很有帮助。 是的,它可以在我的 Windows 7 计算机上运行。当您运行它时,您的计算机上究竟发生了什么?你有什么操作系统?看看 Pastebin 上的代码:pastebin.com/TPegYKqW,pastebin.com/PVqw68f8 当我从第一个对话框的 OnOK() 调用第二个对话框时,此代码确实有效。但是从 CMyTestApp::InitInstance() 调用第二个对话框的代码崩溃了。你确定吗 ?我也在寻找它背后的原因。 好的,所以它没有崩溃,但给出了几个调试断言失败,发布版本工作正常。我进一步发现调试断言是因为语句 m_pMainWnd = &dlg 在这种情况下似乎没有必要。但即便如此,它也不起作用。我们必须在 doModal 之前使用 PM_REMOVE 调用 PeekMessage() 以使其工作 究竟哪些断言失败了?【参考方案2】:当您创建一个无模式对话框时,控制将立即返回到您的调用函数,因此您需要在全局范围内声明变量dlgModeLess
,并确保您的程序/范围在对话框结束之前仍然处于活动状态
【讨论】:
【参考方案3】:我已经解决了这个问题,结果证明这很有趣。
似乎 Cdialog::Create() 本身不足以创建一个完全可操作的无模式对话框。我们必须为其提供一个 win32 样式的消息循环。 所以这有效地在程序中产生了两个消息循环,一个提供我的 MFC 框架,另一个是我从 IDOK 返回后编写的。这是修改后的代码。
CSecondDlg *dlgModeLess = new CSecondDlg();
dlgModeLess->Create(CSecondDlg::IDD,NULL);
CTrayIconDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
// TODO: Place code here to handle when the dialog is
// dismissed with OK
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
MSG leftmsg;
PeekMessage(&leftmsg,m_pMainWnd->m_hWnd,0,0,PM_REMOVE);
MSG msg;
BOOL bRet;
while ((bRet = GetMessage(&msg, dlgModeLess->m_hWnd, 0, 0)) != 0)
if (bRet == -1)
// Handle the error and possibly exit
else if (!IsWindow(hWnd) || !IsDialogMessage(hWnd, &msg))
TranslateMessage(&msg);
DispatchMessage(&msg);
此代码按预期工作,这里要注意的有趣之处是 PeekMessage 函数,该函数会在第一个对话框被解除后删除插入线程的消息队列中的 WM_QUIT 消息,因为我们不想在那个时间点完全关闭.我相信这是由 MFC 框架完成的。
【讨论】:
以上是关于一个 MFC 应用程序中的两个对话框的主要内容,如果未能解决你的问题,请参考以下文章