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的官方文档也是可以的.

却道,此心安处是吾乡
原文地址:https://www.cnblogs.com/lucifer25/p/7812871.html