chapter7 事件处理
chapter7 事件处理
事件(event)是由窗口系统或者Qt自身产生的,用以响应所发生的各类事情.我们在前面已经接触到,在main.cpp的结尾处,我们用:
app.exec();
表示进入应用程序的循环,应用程序会监听各类事件,然后予以相应.
这里我们要区分"事件"和"信号",相较而言,"事件"属于更为底层的触发机制,"信号"可以说是"事件"的一个结果,在使用窗口部件的时候,我们通常是和"信号"打交道,但如果涉及到具体的实现,就要去寻找相应的"事件"了.举个例子:QPushButton有clicked()信号,这个信号的发出,正是由于触发了鼠标的QMouseEvent事件才被emit出来.
在Qt中,事件就是QEvent的子类,子类的类型有很多,可以用QEvent::type()返回枚举值.不过我们通常接触到的,有QMousEvent, QKeyEvent, QPaintEvent等,我们通常可以重写这些事件内部的代码,来实现我们期待的功能.
ticker.h
#ifndef TICKER_H
#define TICKER_H
#include <QWidget>
namespace Ui {
class Ticker;
}
class Ticker : public QWidget
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText)
public:
explicit Ticker(QWidget *parent = 0);
void setText(const QString &newText);
QString text() const { return myText; }
QSize sizeHint() const;
~Ticker();
protected:
void paintEvent(QPaintEvent *event);
void timerEvent(QTimerEvent *event);
void showEvent(QShowEvent *event);
void hideEvent(QHideEvent *event);
private:
Ui::Ticker *ui;
QString myText;
int offset;
int myTimerId;
};
#endif // TICKER_H
可以看出,各类事件基本都是protected的,这里我们重写窗口绘制事件,还有一个定时器时间,一个窗口显示,隐藏事件.
1.重新实现事件处理器
ticker.cpp
#include "ticker.h"
#include "ui_ticker.h"
#include <QPainter>
Ticker::Ticker(QWidget *parent) :
QWidget(parent),
ui(new Ui::Ticker)
{
ui->setupUi(this);
offset = 0;
myTimerId = 0;
}
Ticker::~Ticker()
{
delete ui;
}
void Ticker::setText(const QString &newText){
myText = newText;
update();
updateGeometry();
}
QSize Ticker::sizeHint() const{
return fontMetrics().size(0, text());
}
void Ticker::paintEvent(QPaintEvent *event){
QPainter painter(this);
int textWidth = fontMetrics().width(text());
if(textWidth < 1){
return;
}
int x = -offset;
while(x < width()){
painter.drawText(x, 0, textWidth, height(),
Qt::AlignLeft | Qt::AlignVCenter, text());
x += textWidth;
}
}
void Ticker::showEvent(QShowEvent *event){
myTimerId = startTimer(30);
}
void Ticker::timerEvent(QTimerEvent *event){
if(event->timerId() == myTimerId){
++offset;
if(offset >= fontMetrics().width(text())){
offset = 0;
}
scroll(-1, 0);
}else{
QWidget::timerEvent(event);
}
}
void Ticker::hideEvent(QHideEvent *event){
killTimer(myTimerId);
myTimerId = 0;
}
在调用update()和scroll()的时候,都会触发paintEvent()重新绘制窗体,startTimer(30)是每隔30毫秒,就会发射一个定时器事件,然后用timerEvent()事件来捕捉.
2.事件的传递
事件是作用于具体的对象,但是事件从触发,到进入该对象内部的处理事件函数时,经历了以下几个过程:
父对象的eventFilter()->窗体部件的event()->窗体部件的更具体的事件,如keyPressEvent()->父对象的keyPressEvent()
是有一个传递的过程的,在各个部分,事件都可以选择拦截.比如在窗体部件的keyPressEvent()事件中,如果选择accept(),则事件不会传递给父窗体,而如果选择ignore(),事件就会上浮,被父窗体捕获,引起触发.
还有一个更强的方式,就是为子窗体安装事件过滤器installEvent(),这样事件在到达子窗体之前,会先经过父窗体的eventFilter()事件过滤器,事件过滤器可以自由的编写,判断事件触发的对象,以及触发的类型,可以选择拦截,也可以选择忽略,直接调用父类的eventFiler()函数,执行默认的一些操作,这点而言,是非常重要的.
总结:应该说事件系统是Qt中很重要的部分,但是基本的一些思路,不是很难掌握,当然事件处理中还是有一些比较高级的用法的,很复杂,但是多数情况下并不会用到,因此在需要的时候,再去查看Qt的官方文档也是可以的.