10.Qt事件

事件(event)是由系统或者 Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。一些事件在对用户操作做出响应时发出,如键盘事件等;另一些事件则是由系统自动发出,如计时器事件。
Qt 程序需要在main()函数创建一个QApplication对象,然后调用它的exec()函数。这个函数就是开始 Qt 的事件循环。在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件。当事件发生时,Qt 将创建一个事件对象。Qt 中所有事件类都继承于QEvent。在事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数(event handler),关于这一点,会在后边详细说明。
 
在所有组件的父类QWidget中,定义了很多事件处理的回调函数,如
 
    • keyPressEvent()
    • keyReleaseEvent()
    • mouseDoubleClickEvent()
    • mouseMoveEvent()
    • mousePressEvent()
    • mouseReleaseEvent() 等。
这些函数都是 protected virtual 的,也就是说,我们可以在子类中重新实现这些函数。下面来看一个例子:
class EventLabel : public QLabel
{
protected:
    // 鼠标移动事件
    void mouseMoveEvent(QMouseEvent *event);
    // 鼠标点击事件
    void mousePressEvent(QMouseEvent *event);
    // 鼠标移动事件
    void mouseReleaseEvent(QMouseEvent *event);
    // 进入窗口区域
    void enterEvent(QEvent *);
    // 离开窗口区域
    void leaveEvent(QEvent *);
};
 
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);
}
 
void enterEvent(QEvent *ev)
{
 
}
 
void leaveEvent(QEvent *ev);
{

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

 

 
 
  • EventLabel继承了QLabel,覆盖了mousePressEvent()、mouseMoveEvent()和MouseReleaseEvent()三个函数。我们并没有添加什么功能,只是在鼠标按下(press)、鼠标移动(move)和鼠标释放(release)的时候,把当前鼠标的坐标值显示在这个Label上面。由于QLabel是支持 HTML 代码的,因此我们直接使用了 HTML 代码来格式化文字。
  • QString的arg()函数可以自动替换掉QString中出现的占位符。其占位符以 % 开始,后面是占位符的位置,例如 %1,%2 这种。
QString("[%1, %2]").arg(x).arg(y);
语句将会使用x替换 %1,y替换 %2,因此,生成的QString为[x, y]。
  • 在mouseReleaseEvent()函数中,我们使用了另外一种QString的构造方法。使用类似 C 风格的格式化函数sprintf()来构造QString。
为什么要点击鼠标之后才能在mouseMoveEvent()函数中显示鼠标坐标值?
这是因为QWidget中有一个mouseTracking属性,该属性用于设置是否追踪鼠标。只有鼠标被追踪时,mouseMoveEvent()才会发出。如果mouseTracking是 false(默认即是),组件在至少一次鼠标点击之后,才能够被追踪,也就是能够发出mouseMoveEvent()事件。如果mouseTracking为 true,则mouseMoveEvent()直接可以被发出。
知道了这一点,我们就可以在main()函数中添加如下代码:
label->setMouseTracking(true);
在运行程序就没有这个问题
 
#ifndef WIDGET_H
#define WIDGET_H
 
 
#include <QWidget>
 
 
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
 
 
class Widget : public QWidget
{
    Q_OBJECT
protected:
    // 键盘按键事件
    virtual void keyPressEvent(QKeyEvent *);
    
    // 定时器事件
    virtual void timerEvent(QTimerEvent *);    
 
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
 
 
private:
    Ui::Widget *ui;
    int timerId;
};
#endif // WIDGET_H
 
 
 
 
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QKeyEvent>
 
 
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
 
    // 启动定时器
   timerId =  this->startTimer(1000);    // 毫秒为单位,每个1s触发一次定时器
    // 停止定时器
    this->killTimer(timerId);
}
 
 
void Widget::keyPressEvent(QKeyEvent *ev)
{
    qDebug() << (char)ev->key();
}
 
void Widget::timerEvent(QTimerEvent *ev)
{
    // 如果多定时器
    if(ev->timerId() == this->timerId)
    {
        static int sec = 0;
                sec++;
                ui->label->setText(QString("<center><h1>timer out : %1</h1></center>").arg(sec));
    }
}
 
 
Widget::~Widget()
{
    delete ui;
}

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2021-08-20 16:08  无名之辈jkr  阅读(216)  评论(0编辑  收藏  举报