非模态对话框关闭按钮(“X”)调用OnCancel的疑问

二进制脑袋 2021-04-07 04:48:39
VS2015,MDI应用。要使用一个非模态对话框,发现该对话框的IDCANCEL按钮、ESC按键、窗口右上角的“X”按钮,实际都调用OnCancel虚函数。确认了一下,按窗口右上角的“X”按钮,会触发WM_CLOSE消息,调用OnClose方法,微软的官方文档说OnClose的缺省方法调用DestroyWindow。但我查遍了VC 2015附带的mfc源码,没有找到CDialog或者CDialogEx响应WM_CLOSE消息调用OnCancel的代码实现。哪位对这个比较熟悉,找到非模态对话框的窗口右上角关闭按钮“X”是调用OnCancel证据?官方文档或者mfc源码文件说明都可以。
...全文
449 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
二进制脑袋 2021-04-09
  • 打赏
  • 举报
回复
在《Programming Windows with MFC, Second Edition》,关于非模态对话框,有这么一句话:You should always override OnCancel because an IDCANCEL notification is sent when the user presses the Esc key or clicks the dialog box's close button, regardless of whether the dialog box contains a Cancel button. 算是证实吧,但还是没看到是谁在对话框关闭按钮按下后,投递WM_COMMAND消息的。
二进制脑袋 2021-04-09
  • 打赏
  • 举报
回复
明确了: 1、对话框按IDCANCEL按钮,直接通过ON_COMMAND(IDCANCEL, &CDialog::OnCancel)的消息映射,触发OnCancel的调用; 2、按ESC按键,在CDialog::PreTranslateMessage中,调用CWnd::PreTranslateInput,进而调用CWnd::IsDialogMessage,接下来调用Windows API ::IsDialogMessage,在::IsDialogMessage处理中,直接调用OnCancel; 3、按对话框右上角“X”按钮,如我在上一条回复中所述,缺省的OnClose会调用CWnd::Default,会被(谁?)投递一条WM_COMMAND消息,ID为IDCANCEL,从而触发OnCancel被调用。究竟是谁投递WM_COMMAND的,目前在MFC源码中还没有找到!
二进制脑袋 2021-04-08
  • 打赏
  • 举报
回复
由于VS2015调试不能跟踪MFC源码,转到VS2008调试发现。对话框右上角的“X”按钮,会触发WM_CLOSE消息,响应WM_CLOSE消息,方法为OnClose,如果调用CDialog::OnClose(),则会实际调用CWnd::OnCancelMode(),CWnd::OnCancelMode()和CWnd::OnClose()一样,都会调用CWnd::Default()。进而会调用对话框的OnCancel()方法。究竟调用Default()之后,怎么调用OnCancel的,VS2008中间跟踪断掉了,不得而知。
Eleven 2021-04-08
  • 打赏
  • 举报
回复
When you implement a modeless dialog box, always override the OnCancel member function and call DestroyWindow from within it. Don't call the base class CDialog::OnCancel, because it calls EndDialog, which will make the dialog box invisible but will not destroy it. You should also override PostNcDestroy for modeless dialog boxes in order to delete this, since modeless dialog boxes are usually allocated with new. Modal dialog boxes are usually constructed on the frame and do not need PostNcDestroy cleanup.
zgl7903 2021-04-07
  • 打赏
  • 举报
回复
那个叉 可以 修改风格 (去掉 WS_SYSMENU) 风格, 或者注册类的时候 style加 CS_NOCLOSE 或者消息的话 可以处理 WM_SYSCOMMAND SC_CLOSE
MFC的视图打印/预览功能基于CView::OnFilePrint和CView::OnFilePrintPreview这两个函数 如果要对用户自定义对话框模态)内的子视图(以下简称A视图)进行打印,直接调用A视图的CView::OnFilePrint即可,弹出的“选择打印机”对话框同样也是模态对话框,覆盖在用户对话框上。 如果要对用户对话框内的A视图进行预览,直接调用A视图的CView::OnFilePrintPreview后,预览视图(MFC CPreviewView类实例)内虽然预览正常,但是挡住了用户对话框。由于用户对话框模态的,导致预览视图上的“打印...”、“上一页”、“下一页”、“放大”、“缩小”、“单页/双页”和“关闭”等按钮均无法响应鼠标点击,处于“假死”状态。 解决方法: 在调用A视图的CView::OnFilePrintPreview之前,先关闭用户对话框(CDialog::OnCancel),由于这时已不存在用于预览的A视图,再重新创建一个相同的视图(以下简称B视图),以B视图来启动OnFilePrintPreview进行预览。 MFC视图预览的原理是:以主框架窗口(CMainFrame)作为预览框架,隐藏原先的子视图(用CMainFrame::GetActiveView得到的那个,以下简称C视图),用CPreviewView类替换,同时创建包含“打印...”、“放大”、“关闭”等按钮的工具栏(CDialogBar类),最后将CPreviewView::m_pPreviewDC作为C视图OnDraw的CDC*参数传入,这样,虽然调用的是C视图的OnDraw函数,实际上却显示在了CPreviewView视图中,起到了“预览”的效果。在点击预览框架工具栏上的“打印...”按钮后, MFC体系将向原先的主框架(本例中和预览框架是同一个,都是CMainFrame)发送ID_FILE_PRINT的WM_COMMAND消息。在缺省的配置中,这将启动C视图的OnFilePrint,从而在打印机上打出C视图的内容。 在本例中,为了打印B视图,需要在CMainFrame中处理WM_COMMAND/ID_FILE_PRINT,加入额外的条件,来判断对按钮“打印...”的点击是来自B还是C视图的预览框架。在本例中用了一个变量CMainFrame::m_nPrintFrom。根据其取值(0或者1),分别启动B或者C视图的OnFilePrint。 使用方法: 程序示例在VC++2010上通过。主菜单项“打印预览测试”下,有两个子菜单项,“对话框用户视图的打印预览”用于B视图(画出一个圆);“单文档视图的打印预览”用于C视图(画出一个正方形),等同于“文件”主菜单项下的“打印预览(V)”。

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧