[Effective WX] 有关wxGTK的模态对话框(modal dialog)弹出的非模态窗口的问题
来源:互联网 发布:手机淘宝免费开店流程 编辑:程序博客网 时间:2024/04/29 17:54
wxGTK上有这样的的编程问题:
已经有一个模态对话框(通过ShowModal()显示出来),然后从它上面弹出一个非模态窗口(为什么会是非模态?应该是或者是业务需求,或者是想重用已存在所需功能的非模态窗口类),调用它的Show()函数将其显示出来。结果我们发现,根本就不能再对这个非模态窗口做任何操作。它无法接受任何用户输入,反而它的父窗口(那个模态对话框)仍像之前一样可以接受用户输入。
这篇文章将给出一些浅显的分析和一个可能的解决方案。
1. GTK版本的模态对话框ShowModal()函数到底做了什么?
在$wxsrc/gtk/dialog.cpp文件的135-153行中,ShowModal()做了如下的事情:
135 wxBusyCursorSuspender cs; // temporarily suppress the busy cursor136 137 Show( true );138 139 m_modalShowing = true;140 141 g_openDialogs++;142 143 // NOTE: gtk_window_set_modal internally calls gtk_grab_add() !144 gtk_window_set_modal(GTK_WINDOW(m_widget), TRUE);145 146 wxEventLoop().Run();147 148 gtk_window_set_modal(GTK_WINDOW(m_widget), FALSE);149 150 g_openDialogs--;151 152 return GetReturnCode();153 }它利用gtk代码库,直接新启了一个事件循环。
2. 一个解决方案
3. 上面方案带来的问题,如何解决?
如果你采用上面的方案,可能会发现你仍然无法使用窗口右上角的"X"按钮来关闭这个非模态窗口。
gdb调试代码,你会发现当用户点击"X"按钮后,wx代码库会调用到它注册gtk库的一个callback。代码行处于文件的$wxsrc/src/gtk/toplevel.cpp的260-273行。至于如何定位到是这个函数被调用的,你可以让这个非模态窗口直接创建显示出来,而不是从模态对话框中创建然后显示,设置断点到它的Close Window事件的响应函数,然后浏览它的调用栈就可以定位到这个callback首先被调用。
复现问题时,设置断点到268行,然后检查该行每一判断条件。你会发现g_openDialogs=1, win->GetExtraStyle()没有那个wxTOPLEVEL_EX_DIALOG属性,win->IsGrabbed()返回false,从而271行的win->Close()总是不会调用,进而窗口“X"无法响应的原因,你已清楚。
找到问题的原因,想解决它应该不会太难。
1) g_openDialogs 是一个全局变量,它并没有public出来,只是在dialog的ShowModal函数中会被改写。对这个变量我们最好不要有其它想法。
2) 对于win->GetExtraStyle(),我们在创建非模态窗口前,先增加wxTOPLEVEL_EX_DIALOG属性
win->SetExtraStyle(win->GetExtraStyle() | wxTOPLEVEL_EX_DIALOG)
马上动手试验(需要将非模态窗口加上wxCLOSE属性,让右上角出现“X"),你会发现它可以工作,非模态窗口可以响应"X"关闭事件,而且窗口上的其它控件并没有受任何影响。我想这是个比较好的解决方案。
3) 对于win->IsGrabbed(),这是一个wx对gtk特别处理的函数,定义在gtk版本的子类topwindow类中。跟它一起的还有2个函数AddGrab()和RemoveGrab()。
看下它们的实现就知道了:
1316 void wxTopLevelWindowGTK::AddGrab()1317 {1318 if (!m_grabbed)1319 {1320 m_grabbed = true;1321 gtk_grab_add( m_widget );1322 wxEventLoop().Run();1323 gtk_grab_remove( m_widget );1324 } 1325 } 1326 1327 void wxTopLevelWindowGTK::RemoveGrab()1328 { 1329 if (m_grabbed)1330 { 1331 gtk_main_quit();1332 m_grabbed = false;1333 }1334 }AddGrab()是新启一个事件循环,让这个非模态窗口成为一个模态的。如果我们在非模态窗口显示之后,调用这个函数,应该也可以工作。非模态窗口上的所有控件都可以响应用户输入,包括"X"按钮。但是它更改了之前非模态窗口的设计初衷,可能会带来更多的麻烦。譬如之前非模态窗口上可能会弹出其他的非模态窗口,这样的话,新的非模态窗口就无法接受用户输入了。
4. 更好的解决方案?
- [Effective WX] 有关wxGTK的模态对话框(modal dialog)弹出的非模态窗口的问题
- [Effective WX] wxGTK上popup wxMenu的一个crash问题分析及解决方案
- 模态与非模态对话框 (Modal and Modeless Dialog Boxes)的区别
- Java 源码-模态对话框(Modal Dialog Box)的实现
- [Effective WX] wx的UI UnitTest explained
- 模式窗口(Modal Dialog) 导致 Session丢失的解决办法
- 模态对话框问题:父窗口打开一个模态子窗口后,子窗口的form提交给自己,弹出新窗口
- 有关对话框的问题
- 在asp.net中有关"弹出对话框"的问题
- 关于模态对话框(modal dialog)
- Qt中的模态对话框(Modal Dialog)与非模态对话框(Modeless Dialog)用法
- android 弹出窗口 - 正常的Dialog弹出窗口
- [Effective WX] wxAUIManager在GTK实现上的一些问题
- AngularJs 弹出模态窗口 $modal $uibModal
- [Effective WX] wx中的反射机制:DANYMIC_CLASS的实现
- 有关弹出是窗口的误区
- MFC 关闭所有弹出模态对话框,并创建新的对话框(切换/跳转窗口)
- AfxMessageBox弹出的对话框时,关闭父窗口的父窗口引起的问题。
- SpingMVC registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the we
- SQL SERVER 文件自动增长和自动收缩
- 关于java的包(1)
- Matlab中的程序执行速度为什么很慢?
- 输入一串数并对其求和
- [Effective WX] 有关wxGTK的模态对话框(modal dialog)弹出的非模态窗口的问题
- 我的2013----IT女的一年经历
- linux下解压命令
- C++ string实现
- 小妹的美好时代
- 2013秋13级预备队集训练习4 --C - The Land of Justice
- 10个迷惑新手的Cocoa,Objective-c开发难点和问题
- android 手电筒开发
- 数据结构开发日志