QT的事件机制

来源:互联网 发布:大数据hadoop面试题 编辑:程序博客网 时间:2024/05/18 02:41

         刚开始学习QT这几天被QT的事件机制搞的头都大了,一直不懂的事件是怎么传递的 于是就做了一些测试,结合别人的分析,得出了自己的一点心得。

    首先要明白什么是事件,我们这里从窗口中button控件来解释,当你的鼠标移动到button上时候,点击鼠标的时候,系统就会向你的控件发送事件信息,这样如果你button类封装了对事件做出反应的函数,则会有相应的事件反馈产生。这里就会牵扯到问题,A.具体有哪几种事件,B.事件是产生后立马就反馈,还是存储到什么地方,C.究竟在QT中事件是怎么传递的问题。

     针对A问题,直接百度就可以发现很多技术blog的文章,事件分为三类:1.系统窗口产生的spontaneous事件 2.应用程序或者Qt发送的post事件 3.应用程序或者Qt发送的SEND事件。A问题已经知道了,B问题就不难了,对于类别1的事件,它被系统放入事件队列中排序(我们不难发现,每一个Qt主程序中都会有一个application对象,然后会有exec()函数内部会有一个eventloop存储消息)。对于类别2事件,类似与1同样会有一个事件序列。对于类别3事件会立马将事件发送给事件的目标对象。

     针对C问题,结合QT中widget类event的源代码和自己做的一些小测试(建立三个类,dialog(继承QDialog),button(继承QPushButton),lineedit(继承)Qline edit),我们通过分别重定义类的event函数,eventfilter函数,对对象安装事件过滤器,不难发现(只粗略研究了类别1事件的传递过程)首先类别1事件,由notify()函数将序列中的事件分发给要传递的对象,这个对象首先会检查自己是否安装了事件过滤器,当对象安装了事件过滤器后,对象的一个成员变量会保存对它安装过滤器的对象的指针,例如对象B安装对象过滤器,而此对象过滤器的所有者是对象A,则B对象会保存A对象的指针,当notify函数将事件分发给B对象的时候,由于安装了事件过滤器,则事件会传递给A对象来出来,A对象如果重载了bool eventfilter(QEvent *e)函数,就能进行相应的处理了,这里bool eventfilter(QEvent *e)函数返回了一个bool值用来与notify沟通,当值为真则表示事件不再需要传递了,而当返回值为假的时候就要通过notify继续分发处理,这时这个事件会传递给对象B的bool event(QEvent *e)函数,这里返回值和eventfilter的返回值作用是相同的,都是通过bool值来告知事件是否需要继续分发传递。当这是还返回false的时候,事件就会传递给事件所属对象的父类对象(容器),举个例子就是如果你的button控件的event函数都处理完成事件后继续传递事件,这时notify函数就会将事件分发给button从属的容器(例如对话框),直到返回true值或者是到达顶层的widget对象的时候对事件的处理才会结束。

        这里我们不难得出一个结论,上面介绍的eventfilter函数与event函数是与分发函数notify来沟通的,来通过传递bool值来让notify知道事件是否需要继续传递下去。这里有一个小插曲,Qt自己定义了非常具体的事件处理函数,如mousebuttonpress函数类似函数,来处理非常具体的对象,实际上当事件传递给对象的时候也是通过先进入event函数再来找到最具体的事件处理函数,只不过这些非常具体的事件处理函数通过ignore()和accept函数来与event函数来沟通,具体来说就是ignore来表明要继续往下再传递事件了,accept表示不要继续往下传递事件了,然后event()函数获取这个信息后 就会将其转化为自己的返回值来告知notify函数需不需要继续传递事件了,具体事件处理函数默认accept(true),

       最后总结在编程的时候需要注意的一些特殊情况,实际上我们一般来重定义最具体的函数来处理事件,这几乎满足了大多数需求,当我们重新定义的时候要记住,因为我们处理的是具体的特殊事件,我们并不知道我们的对象是否还需要处理其他的事件,定义函数的时候就需要处理完了特殊事件后加上一句return parent(基类)::spcific fun(...)(具体的事件处理函数),这样才不会因为重定义覆盖了基类的具体事件处理函数而导致的一些特殊问题。而还有一些具体事件处理函数比较特殊,例如presskeydown()函数,默认是对按下tab键会使得光标从一个小部件移动到令一个小部件,假使我们需要对tab键做我们自己的事件处理,这时我们只需从定义覆盖覆盖event函数,这里也必须注意在处理完成后,其他的事件直接returned 基类的event()函数,还是那个原因 ,你并不知道派生类对象的基类子对象会需要对哪些事件做出默认的反馈。当然在我们重定义覆盖的函数,我们通过设置标志位如accept函数,或者返回bool值来指明我们具体还是否需要事件具体传递。

其他两种事件类似这个传递过程,应该只有小小的差别(猜的)。

 

0 0
原创粉丝点击