• 6436阅读
  • 7回复

求解Qt消息处理机制,或是类似东西 [复制链接]

上一主题 下一主题
离线mpcrm
 
只看楼主 倒序阅读 楼主  发表于: 2013-08-05
关键词: QT4
最近工作需要,其实自己也想搞清楚一些东西,主要是Qt的消息处理机制,涉及到UI主线程,QEventLoop,模态对话框的eventloop与主eventloop(QApplication的exec())的关系等等。


以一个简单例子为例:在主窗口MainWindow上点击一个按钮后,弹出一个模态对话框A:
[size=; font-size: 1em,1em][font=Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace]MainWindow::OnBtnClicked()
{
A a(this);//仅作示例用,所以用局部变量,它也完全可以是局部指针,或MainWindow的成员变量
a.exec();

if (...)//这里判断用于点击的A上的按钮,这个返回值可能是Qt默认的accepted(),rejected(),
//也可能是用户自己定义的一些返回值(如自定义对话框,多个按钮多个返回值,
//如Selection_OK, Selection_Cancel等等)
{
...
}
else
{
...
}
...
}


很简单的一个示例,已经包含了一些东西:


1. 假如不存在主动创建的其他worker线程的话,这里目前为止就涉及到一个UI线程,也就是主线程,MainWindow和A都是执行在主线程上的。


2. 虽然A是模态对话框,看起来整个程序似乎Block在a.exec()这里一样(A这里创建了一个局部事件循环QEventLoop),并不意味着程序只能执行作用在A上的键盘鼠标消息,程序也可以执行其它的消息的(假如程序存在一个串口接收数据的线程,接收到的数据可以通过异步信号槽函数由主线程实时显示到MainWindow上)。这些是我的理解,但疑问是,依这个理解的话,程序只是貌似Block在a.exec()上,其实主线程并没有block;但是a.exec是执行在主线程上的,它为什么不会block主线程,除非他又隐式创建了一个线程,但事实又并非如此。这里涉及到主线程和多个eventloop,是我不理解的地方之一。


dbzhang800 blog文章(QDialog 模态对话框与事件循环http://blog.csdn.net/dbzhang800/article/details/6300416)中的一段话:

"对与QDialog来说,当它自己的QEventLoop启用时,主程序的 QEventLoop 当然是处于暂停状态了。说到底,就是两个死循环,一个在内,一个在外,只有里面的退出后,外边的循环才会执行。不过由于两个循环执行的命令是基本一样的,都是调用并处理程序收到的各种事件,所以,可能变得不容易理解"

完全不能理解……



3. 假如此时串口接收数据的线程接收到一个指令,通过异步信号槽函数由主线程隐藏或者关闭或者销毁A(这些是完全可以的吧),那么此时正在执行的(或者说,正在block中的)MainWindow::OnBtnClicked()会发生什么事?其中的a.exec()返回?它之后的代码继续执行?这是我另一个难以理解的地方。


以上是我目前的一些理解和疑问,可能比较混乱,最近一直在考虑这些问题,也看了dbzhang800 blog上的一些文章,依然混乱,希望有大神能指点一二,或者给出些相关文章,谢谢!
离线dbzhang800

只看该作者 1楼 发表于: 2013-08-05
可以类比,

  1. while(1) {
  2. 交警指挥交通
  3. if (some case) {
  4. while(1)
  5. 协警指挥交通
  6. }
  7. }
  8. }
一个个的事件相当于路上的行人车辆。

离线mpcrm
只看该作者 2楼 发表于: 2013-08-05
引用第1楼dbzhang800于2013-08-05 15:37发表的  :
可以类比,
[code]while(1) {
交警指挥交通
.......

大神终于来了啊~


那是不是是这样:

代码运行到a.exec()这里,相当于是处在内部的循环了。那此时,另外一个线程发送一个信号让MainWindow显示一个东西,这一步也是在内部的这个循环做的? 更进一步说,在a.exec()导致的事件循环未退出前,所有的代码处理都是在a.exec()这个内部循环做的了?


如果是这样的话,我提到的第3点,另一个worker线程发送一个信号让处在主线程中的MainWindow隐藏a, 执行的话,就是在内部循环中让a隐藏,之后,内部循环结束,a.exec()返回,a.exec()后的代码在外部循环中继续执行。是这样子吗?
离线dbzhang800

只看该作者 3楼 发表于: 2013-08-05
对。

但这么做很可能会导致程序崩溃。Qt官方blog中有提及这些问题,这也是为什么官方会推荐使用QDialog::open() 而不是 QDialog::exec() 的原因。

你可以从这儿开始 http://blog.csdn.net/dbzhang800/article/details/6889291
离线mpcrm
只看该作者 4楼 发表于: 2013-08-05
引用第3楼dbzhang800于2013-08-05 16:39发表的  :
对。
但这么做很可能会导致程序崩溃。Qt官方blog中有提及这些问题,这也是为什么官方会推荐使用QDialog::open() 而不是 QDialog::exec() 的原因。
你可以从这儿开始 http://blog.csdn.net/dbzhang800/article/details/6889291

这篇文章及其中引用的一些官方链接,我都看过了


但是因为我没找到太多关于open()的描述,下面是我对于open()初步理解:
1. 使用open,则其上的一些按钮(可以使其关闭的按钮)的响应必须在open()前用信号和槽的方式实现?
2.open可以让对话框看起来是模态的,但是不会产生局部事件循环
3. 在对话框的构造函数中:    setWindowModality(Qt::WindowModal);
然后,调用其show()进行显示,此时对话框还是模态的,还是会创建事件循环,是吗?-----试了下,是windowModal模态,好像不会创建事件循环


可能有的问题比较白,见谅……


谢谢!
离线mpcrm
只看该作者 5楼 发表于: 2013-08-05
对了,QtQuarterly30 之 New Ways of Using Dialogs
这个链接打不开了,能否提供一下新的链接,谢谢!
离线dbzhang800

只看该作者 6楼 发表于: 2013-08-06
1. 只有 exec() 会创建事件循环

2. 新的链接你google的话,第一个应该就是
离线mpcrm
只看该作者 7楼 发表于: 2013-08-06
嗯,明白了

那个文档也下到了

非常感谢哈!
快速回复
限100 字节
 
上一个 下一个