QT之事件系统

QT的事件系统通过QEvent类派生各种事件,并通过event()函数传递。事件类型包括QResizeEvent、QPaintEvent等,处理方式包括重写事件处理函数、事件过滤器等。自定义事件需继承QEvent,注册事件类型以避免冲突。文章通过一个MyEvent的示例演示了自定义事件的创建和处理。
摘要由CSDN通过智能技术生成

1. 概述

在QT中,事件均派生自QEvent抽象类,事件可以由任何派生自QObject的子类实例接收和处理。它们与widget关联性极强。

2. 事件的传递

当事件发生时,QT 通过构造适当的 QEvent 子类实例来创建一个事件对象来表示它,并通过调用其 event() 函数将其传递给 QObject 的特定实例

event() 函数本身不处理事件;它根据传递的事件类型,它会调用该特定类型事件的事件处理程序,并根据事件是被接受还是被忽略来发送响应。

传递的顺序如下:
在这里插入图片描述

3. 事件类型

大多数事件类型都有特殊的类,特别是 QResizeEvent、QPaintEvent、QMouseEvent、QKeyEvent 和 QCloseEvent。 每个类都是 QEvent 的子类并添加特定于事件的函数。 例如,QResizeEvent 添加了 size() 和 oldSize() 以使小部件能够发现它们的尺寸是如何改变的。

每个事件都有一个关联的类型,在 QEvent::Type 中定义,这可以用作运行时类型信息的方便来源,以快速确定给定事件对象是从哪个子类构造的。

具体的事件类型可参考,官网介绍

4. 事件处理与事件过滤

常用的事件处理方式如下:

  • 重写各种事件的虚函数
    如paintEvent()、mousePressEvent()等。这是最常见的方式,同时也是最简单和功能最弱的方式
  • 重写event()函数
    event()函数是所有对象的事件入口,QObject和QWidget中的实现,默认是把事件传递给特定的事件处理函数
  • 在特定对象上面安装事件过滤器
    该过滤器仅过滤该对象接收到的事件。
  • 在QCoreApplication::instance()上面安装事件过滤器
    该过滤器将过滤所有对象的所有事件,因此和notify()函数一样强大,但是它更灵活,因为可以安装多个过滤器。全局的事件过滤器可以看到 disabled 组件上面发出的鼠标事件。全局过滤器有一个问题:只能用在主线程。
  • 重写QCoreApplication::notify()函数
    这是最强大的,和全局事件过滤器一样提供完全控制,并且不受线程的限制。但是全局范围内只能有一个被使用(因为QCoreApplication是单例的)
    Qt 调用 QApplication 来发送一个事件,重新实现 notify()函数是在事件过滤器得到所有事件之前获得它们的唯一方法。事件过滤器使用更为便利。因为可以同时有多个事件过滤器。而 notify()函数只有一个。

5. 自定义事件

QT自定义事件的创建步骤如下:

  1. 继承QEvent类
  2. 定义一个事件类型的两种方式
    • QT中有两个宏用来定义了用户事件的最大边界(QEvent::MaxUser)和最小边界(QEvent::User)
    • QT事件系统注册自定义事件类型
      在上述步骤中可以创建出一个与系统事件类型不冲突的自定义事件类型,但是无法保证自定义事件类型不冲突。因此需要将自定义事件类型注册到QT事件系统中,这样若有相同的类型再次被注册时QT事件系统就可以处理自定义事件类型冲突的问题。注册函数如下:
      // 线程安全
      // registerEventType 若传入参数可用则返回此参数,否则返回QEvent::MaxUser和QEvent::User之间的值,若参数不在QEvent::MaxUser和QEvent::User之间则忽略参数
      static int QEvent::registerEventType ( int hint = -1 );
      

5.1 Demo

  • myevent.h
    #ifndef MYEVENT_H
    #define MYEVENT_H
    
    #include <QEvent>
    
    class MyEvent : public QEvent
    {
    public:
        MyEvent();
        int getValue();
        static Type eventType;
    private:
        int m_value;
    };
    
    #endif // MYEVENT_H
    
    
  • myevent.cpp
    #include "myevent.h"
    
    QEvent::Type MyEvent::eventType = (QEvent::Type)QEvent::registerEventType();
    MyEvent::MyEvent(): QEvent(eventType),
        m_value(1)
    {
    }
    
    int MyEvent::getValue()
    {
        return m_value;
    }
    
    
  • mainwindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
        virtual bool event(QEvent *event) override;
    protected:
        // 自定义事件的处理(专门处理自定义事件的),也可以用event()函数处理
        virtual void customEvent(QEvent *event) override;
    private:
        Ui::MainWindow *ui;
    };
    #endif // MAINWINDOW_H
    
    
  • mainwindow.cpp
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "myevent.h"
    #include <QDebug>
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        MyEvent* myEvent = new MyEvent;
        // 事件只能定义在堆上,不用手动释放,系统会自动释放
        qApp->postEvent(this,myEvent);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    bool MainWindow::event(QEvent *event)
    {
        QEvent::Type eventType = event->type();
        if(eventType == MyEvent::eventType)
        {
            MyEvent* myEvent = dynamic_cast<MyEvent*>(event);
            qDebug() << "event" << eventType ;
            qDebug() << "event" << myEvent->getValue() ;
            event->ignore();
        }
        // 处理完成后继续传播事件,这样customEvent就会收到自定义事件
        return QObject::event(event);
    }
    
    void MainWindow::customEvent(QEvent *event)
    {
        QEvent::Type eventType = event->type();
        if(eventType == MyEvent::eventType)
        {
            // 这里默认是true
            qDebug() << "customEvent" << event->isAccepted();
            MyEvent* myEvent = dynamic_cast<MyEvent*>(event);
            qDebug() << "customEvent" << eventType ;
            qDebug() << "customEvent" << myEvent->getValue() ;
            //event->accept();
        }
    }
    

event()处理事件的时机比customEvent()处理的早

6. 发送事件

  1. sendEvent()
    sendEvent() 立即处理事件。 当它返回时,事件过滤器和/或对象本身已经处理了该事件。
    对于许多事件类,有一个名为 isAccepted() 的函数可以告诉您事件是被调用的最后一个处理程序接受还是拒绝。
  2. postEvent()
    postEvent() 将事件发布到队列中以供稍后分派。 下次 Qt 的主事件循环运行时,它会调度所有已发布的事件,并进行一些优化。 例如,如果有多个调整大小事件,它们将被压缩为一个。
    这同样适用于绘制事件:QWidget::update() 调用 postEvent(),它通过避免多次重绘来消除闪烁并提高速度。

7. 参考

  1. QT事件处理–notify()
  2. https://blog.csdn.net/qq_40729688/article/details/89500394
  3. 官方事件系统介绍文档
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Qt是一个功能强大的跨平台应用程序开发框架,其中包含了对系统鼠标事件的检测和处理的功能。 Qt提供了一个名为QMouseEvent的类,用于处理鼠标事件。可以通过重写QWidget或QGraphicsItem中的mousePressEvent()、mouseMoveEvent()和mouseReleaseEvent()等函数来检测鼠标按下、移动和释放等事件。 在该类的对应函数中,可以通过调用event->pos()获取鼠标事件发生时的坐标位置。还可以使用event->button()来获取按下的鼠标按钮,如左键、右键等。Qt还提供了其他的函数和属性,使开发人员可以更精确地获取和处理鼠标事件的各种属性。 通过重写鼠标事件函数并编写自定义的响应代码,可以实现对系统鼠标事件的检测和处理。例如,可以在鼠标按下事件中显示一个提示框,或者在鼠标移动事件中改变鼠标光标的样式。 总结来说,Qt提供了丰富的功能和工具来检测和处理系统鼠标事件。开发人员可以根据具体的需求,通过重写相应的函数来实现对鼠标事件的检测和处理,从而实现更加灵活和个性化的用户交互体验。 ### 回答2: 在Qt中,可以通过重写QWidget或QMainWindow的鼠标事件函数来检测系统鼠标事件。 具体步骤如下: 1. 首先,在自定义的窗口类中重写鼠标事件函数,例如鼠标按下事件(QMouseEvent)、鼠标移动事件(QMouseEvent)等。 例如,在重写鼠标按下事件函数(mousePressEvent)时,可以添加以下代码: ```cpp void MyWidget::mousePressEvent(QMouseEvent *event) { // 获取鼠标按下的坐标位置 QPoint pos = event->pos(); // 根据需要进行其他处理,如判断鼠标按下的位置是否在某个区域内等 // 调用父类的鼠标事件函数,保证正常的事件传递 QWidget::mousePressEvent(event); } ``` 2. 然后,通过创建自定义的窗口对象并显示出来,启动Qt事件循环,使窗口能够接收鼠标事件并进行处理。 例如,在主函数中创建窗口对象并显示: ```cpp int main(int argc, char *argv[]) { QApplication a(argc, argv); MyWidget w; w.show(); return a.exec(); } ``` 通过重写鼠标事件函数,我们可以根据具体需要来获取并处理系统鼠标事件,如鼠标按下、鼠标移动、鼠标释放等,从而实现对这些事件的检测和响应。 ### 回答3: Qt是一种流行的跨平台应用程序开发框架,它提供了许多用于检测与处理鼠标事件的功能。 要检测系统鼠标事件,首先需要创建一个Qt应用程序并设置窗口。然后,可以通过重写窗口类的相关事件处理函数来检测鼠标事件。以下是一个示例代码,演示如何使用Qt检测系统鼠标事件: ```cpp #include <QApplication> #include <QMainWindow> #include <QMouseEvent> #include <QMessageBox> class MyMainWindow : public QMainWindow { public: MyMainWindow(QWidget *parent = nullptr) : QMainWindow(parent) { // 设置窗口属性,使之接收鼠标事件 setMouseTracking(true); } protected: // 鼠标移动事件处理函数 void mouseMoveEvent(QMouseEvent *event) override { // 获取鼠标当前位置 int x = event->x(); int y = event->y(); // 在消息框中显示鼠标位置信息 QString message = QString("鼠标当前位置:(%1, %2)").arg(x).arg(y); QMessageBox::information(this, "鼠标移动事件", message); } // 鼠标点击事件处理函数 void mousePressEvent(QMouseEvent *event) override { // 获取鼠标点击位置和按钮 int x = event->x(); int y = event->y(); Qt::MouseButton button = event->button(); // 在消息框中显示鼠标点击信息 QString message = QString("鼠标点击事件:(%1, %2),按钮:%3").arg(x).arg(y).arg(button); QMessageBox::information(this, "鼠标点击事件", message); } }; int main(int argc, char *argv[]) { QApplication app(argc, argv); MyMainWindow mainWindow; mainWindow.show(); return app.exec(); } ``` 以上示例代码创建了一个自定义的MainWindow类,它继承自QMainWindow,并重写了鼠标移动事件处理函数和鼠标点击事件处理函数。在这些函数中,可以获取鼠标位置和按钮信息,并根据需要进行处理。可以使用QMessageBox来显示事件信息。 通过以上代码,我们可以实现系统鼠标事件的检测,例如获取鼠标位置、检测鼠标点击等。具体根据需求可以进行更多的处理及扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值