Qt事件和信号的比较

这几天看Qt的书,看到事件和信号比较糊涂,傻傻的分不清,百度到豆子空间的一篇文章
http://devbean.blog.51cto.com/448512/223974/

事件和信号

事件(event)是有系统或者Qt本身在不同的时刻发出的。当用户按下鼠标,敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。一些事件是在对用户操作做出响应的时候发出,如键盘事件等;另一些事件则是由系统自动发出,如计时器事件。一般来说,使用Qt编程时,我们并不会把主要精力放在事件上,因为在Qt中,需要我们关心的事件总会发出一个信号。比如,我们关心的是QPushButton的鼠标点击,但我们不需要关心这个鼠标点击事件,而是关心它的clicked()信号。这与其他的一些框架不同:在Swing中,你所要关心的是JButton的ActionListener这个点击事件。

Qt的事件很容易和信号槽混淆。这里简单的说明一下

  • signal由具体对象发出,然后会马上交给由connect函数连接的slot进行处理;
  • 而对于事件,Qt使用一个事件队列对所有发出的事件进行维护,当新的事件产生时,会被追加到事件队列的尾部,前一个事件完成后,取出后面的事件进行处理。

但是,必要的时候,Qt的事件也是可以不进入事件队列,而是直接处理的。并且,事件还可以使用“事件过滤器”进行过滤。总的来说,如果我们使用组件,我们关心的是信号槽;如果我们自定义组件,我们关心的是事件。因为我们可以通过事件来改变组件的默认操作。比如,如果我们要自定义一个QPushButton,那么我们就需要重写它的鼠标点击事件和键盘处理事件,并且在恰当的时候发出clicked()信号。

还记得我们在main函数里面创建了一个QApplication对象,然后调用了它的exec()函数吗?其实,这个函数就是开始Qt的事件循环。在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件。当事件发生时,Qt将创建一个事件对象。Qt的所有事件都继承于QEvent类。在事件对象创建完毕后,Qt将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数(event handler)。关于这一点,我们会在以后的章节中详细说明。

在所有组件的父类QWidget中,定义了很多事件处理函数,如keyPressEvent()、keyReleaseEvent()、mouseDoubleClickEvent()、mouseMoveEvent ()、mousePressEvent()、mouseReleaseEvent()等。这些函数都是protected virtual的,也就是说,我们应该在子类中重定义这些函数。下面来看一个例子。

 #include <QApplication> 
#include <QWidget> 
#include <QLabel> 
#include <QMouseEvent> 

class EventLabel : public QLabel 
{ 

protected: 
        void mouseMoveEvent(QMouseEvent *event); 
        void mousePressEvent(QMouseEvent *event); 
        void mouseReleaseEvent(QMouseEvent *event); 
}; 

void EventLabel::mouseMoveEvent(QMouseEvent *event) 
{ 
        this->setText(QString("<center><h1>Move: (%1, %2)</h1></center>") 
              .arg(QString::number(event->x()), QString::number(event->y()))); 
} 

void EventLabel::mousePressEvent(QMouseEvent *event) 
{ 
        this->setText(QString("<center><h1>Press: (%1, %2)</h1></center>") 
               .arg(QString::number(event->x()), QString::number(event->y()))); 
} 

void EventLabel::mouseReleaseEvent(QMouseEvent *event) 
{ 
        QString msg; 
        msg.sprintf("<center><h1>Release: (%d, %d)</h1></center>",  event->x(), event->y()); 
        this->setText(msg); 
} 

int main(int argc, char *argv[]) 
{ 
        QApplication app(argc, argv); 
        EventLabel *label = new EventLabel; 
        label->setWindowTitle("MouseEvent Demo"); 
        label->resize(300, 200); 
        label->show(); 
        return app.exec(); 
}

这里我们继承了QLabel类,重写了mousePressEvent、mouseMoveEvent和MouseReleaseEvent三个函数。我们并没有添加什么功能,只是在鼠标按下(press)、鼠标移动(move)和鼠标释放(release)时把坐标显示在这个Label上面。注意我们在mouseReleaseEvent函数里面有关QString的构造。我们没有使用arg参数的方式,而是使用C语言风格的sprintf来构造QString对象,如果你对C语法很熟悉(估计很多C+++程序员都会比较熟悉的吧),那么就可以在Qt中试试熟悉的C格式化写法啦!

本文出自 “豆子空间” 博客,请务必保留此出处http://devbean.blog.51cto.com/448512/223974

事件和信号的处理

事件与信号其实并无多大差别,从我们对其需求上来说,都只要能注册事件或信号响应函数,在事件或信号产生时能够被通知到即可。但有一项区别在 于,事件处理函数的返回值是有意义的,我们要根据这个返回值来确定是否还要继续事件的处理,比如在QT中,事件处理函数如果返回true,则这个事件处理 已完成,QApplication会接着处理下一个事件,而如果返回false,那么事件分派函数会继续向上寻找下一个可以处理该事件的注册方法。信号处 理函数的返回值对信号分派器来说是无意义的。

另外还有一个需要我们关注的问题是事件和信号处理时的优先级问题。在QT中,事件因为都是与窗口相关的,所以事件回调时都是从当前窗口开始,一级一级向上 派发,直到有一个窗口返回true,截断了事件的处理为止。对于信号的处理则比较简单,默认是没有顺序的,如果需要明确的顺序,可以在信号注册时显示地指 明槽的位置。

在QT中,事件使用了一个事件队列来维护,如果事件的处理中又产生了新的事件,那么新的事件会加入到队列尾,直到当前事件处理完毕后, QApplication再去队列头取下一个事件来处理。而信号的处理方式有些不同,信号处理是立即回调的,也就是一个信号产生后,他上面所注册的所有槽 都会立即被回调。这样就会产生一个递归调用的问题,比如某个信号处理器中又产生了一个信号,会使得信号的处理像一棵树一样的展开。

Qt提供了发送事件的功能,有QCoreApplication类的设备、sendEvent()函数或postEvent()函数实现。
sendEvent()会立即处理给定的事件,而postEvent()则会将事件放到事件等待调度队列中,当下一次Qt的住时间循环时才会处理它。两个函数还有一点区别,sendEvent()中的QEvent对象参数在事件发送完成后无法自动删除,所以需要到栈上创建QEvent;;;而postEvent()中的QEvent对象参数必须在堆上创建(new一个),当事件被发送后事件队列会自动删除它。

1. 事件的处理
a) 重新实现不见的事件处理函数,比如paintEvent(),mousePressEvent(),这种方法可以用来处理特定部件的特定事件
b) 重新实现notify()函数。这个函数提供了完全控制,可以在事件过滤器得到事件之前处理他们,但是一次只能处理一个事件
c) 想QApplication对象上安装事件过滤器。使用事件过滤器处理事件
d) 重新实现event()函数,QObject类的ecent()函数可以在事件到达默认的事件处理函数之前获得该事件
e) 在对象上安装事件过滤器,使用事件过滤器可以在一个界面类中同时处理不同部件的的不同事件

2. 信号的处理
这个就是通过槽函数处理信号

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值