当前位置: 首页 > article >正文

Qt中的事件模型

Qt中的事件模型

Qt 的事件模型是其核心机制之一,用于处理用户交互(如鼠标点击、键盘输入)以及系统事件(如窗口大小改变、定时器事件等)。以下是 Qt 事件模型的详细介绍:

1. 事件的定义

在Qt 中事件是通过QEvent和其子类来表示的,QEvent是一个抽象基类,定义了事件的基本结构,而具体的事件类型(如鼠标事件、键盘事件、定时器事件等),则通过继承QEvent来实现。

例如:

QMouseEvent:鼠标事件。

QKeyEvent:键盘事件。

QResizeEvent:表示窗口大小改变事件。

QTimerEvent:表示定时器事件。

在QtCreator的帮助中看到,QEvent被很多类继承:

微信截图_20250302142706

2. 事件的产生

事件的产生通常由系统或Qt框架触发。

  • 用户移动鼠标时,系统会生成一个鼠标移动事件。
  • 窗口大小改变时,Qt 会生成一个窗口大小改变事件。
  • 定时器超时时,Qt 会生成一个定时器事件。

3. 事件的传递机制

Qt 的事件模型基于事件的传递和处理机制。事件从产生到被处理,通常会经历以下过程:

3.1 事件的传递链:

事件从产生后,会按照一定的顺序传递给目标对象(通常是窗口或控件),传递顺序如下:

1.事件过滤器(Event Filter):如果某个事件安装了事件过滤器(通过installEventFilter()),事件首先传递给事件过滤器,事件过滤器可以首先对事件进行预处理或者拦截。

2事件处理器(Event Handler):如果事件没有被事件过滤器拦截,它会传递到目标对象的事件处理器。事件处理器是一个虚函数,通常以event()的形式存在。

3.默认事件处理器(Default Event Handler):如果事件没有被目标对象处理,事件会传递给父对象(父窗口)。如果父对象也没有处理事件,最终会传递到 Qt 的默认事件处理器,由 Qt 进行默认处理。

3.2 事件的处理方式

事件的处理方式主要分为以下几种:

1.**事件处理器(event() 函数)**每个QObject派生类都有一个event()对象,用于处理事件,如果需要自定义事件处理逻辑,可以重写该函数。

QObject类有一个event()的虚函数。

微信截图_20250302144601

例如:

  if(e->type() == QEvent::KeyPress)
    {
        // 自定义键盘处理逻辑
        QMessageBox::information(nullptr,"键盘被点击","这是一个信息弹窗");
        // 表示事件已被处理
        return true;
    }
    // 调用父类事件处理器
    return QWidget::event(e);

2。事件过滤器(eventFilter() 函数):事件过滤器是一个全局的事件处理机制,可以拦截并处理其他对象的事件。通过重写 eventFilter() 函数并安装事件过滤器,可以实现对事件的预处理或拦截。

 class MainWindow : public QMainWindow
 {
 public:
     MainWindow();

 protected:
     bool eventFilter(QObject *obj, QEvent *ev) override;

 private:
     QTextEdit *textEdit;
 };

 MainWindow::MainWindow()
 {
     textEdit = new QTextEdit;
     setCentralWidget(textEdit);

     textEdit->installEventFilter(this);
 }

 bool MainWindow::eventFilter(QObject *obj, QEvent *event)
 {
     if (obj == textEdit) {
         if (event->type() == QEvent::KeyPress) {
             QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
             qDebug() << "Ate key press" << keyEvent->key();
             return true;
         } else {
             return false;
         }
     } else {
         // pass the event on to the parent class
         return QMainWindow::eventFilter(obj, event);
     }
 }

3.专用事件处理函数

Qt 提供了一些专用的事件处理函数,如 mousePressEvent()keyPressEvent() 等。这些函数是 event() 函数的特例,用于处理特定类型的事件。如果需要处理特定事件,可以重写这些函数。

void mousePressEvent(QMouseEvent* e) override {
    // 自定义鼠标点击事件处理逻辑
}

4. 事件的类型

Qt 定义了多种事件类型,每种事件类型都有一个唯一的枚举值(QEvent::Type)。以下是一些常见的事件类型:

  • QEvent::KeyPressQEvent::KeyRelease:键盘按下和释放事件。
  • QEvent::MouseButtonPressQEvent::MouseButtonRelease:鼠标按钮按下和释放事件。
  • QEvent::MouseMove:鼠标移动事件。
  • QEvent::Resize:窗口大小改变事件。
  • QEvent::Timer:定时器事件。
  • QEvent::Paint:绘图事件。

在QEvent的源码中有:

enum Type {
        /*
          If you get a strange compiler error on the line with None,
          it's probably because you're also including X11 headers,
          which #define the symbol None. Put the X11 includes after
          the Qt includes to solve this problem.
        */
        None = 0,                               // invalid event
        Timer = 1,                              // timer event
        MouseButtonPress = 2,                   // mouse button pressed
        MouseButtonRelease = 3,                 // mouse button released
        MouseButtonDblClick = 4,                // mouse button double click
        MouseMove = 5,                          // mouse move
        KeyPress = 6,                           // key pressed
        KeyRelease = 7,                         // key released
        FocusIn = 8,                            // keyboard focus received
        FocusOut = 9,                           // keyboard focus lost
        FocusAboutToChange = 23,                // keyboard focus is about to be lost
        Enter = 10,                             // mouse enters widget
        Leave = 11,                             // mouse leaves widget
        Paint = 12,                             // paint widget
        Move = 13,                              // move widget
        Resize = 14,                            // resize widget
        Create = 15,                            // after widget creation
        Destroy = 16,                           // during widget destruction
        Show = 17,                              // widget is shown
        Hide = 18,                              // widget is hidden
        Close = 19,                             // request to close widget
        Quit = 20,                              // request to quit application
        ParentChange = 21,                      // widget has been reparented
        ParentAboutToChange = 131,              // sent just before the parent change is done
        ThreadChange = 22,                      // object has changed threads
        WindowActivate = 24,                    // window was activated
        WindowDeactivate = 25,                  // window was deactivated
        ShowToParent = 26,                      // widget is shown to parent
        HideToParent = 27,                      // widget is hidden to parent
        Wheel = 31,                             // wheel event
        WindowTitleChange = 33,                 // window title changed
        WindowIconChange = 34,                  // icon changed
        ApplicationWindowIconChange = 35,       // application icon changed
        ApplicationFontChange = 36,             // application font changed
        ApplicationLayoutDirectionChange = 37,  // application layout direction changed
        ApplicationPaletteChange = 38,          // application palette changed
        PaletteChange = 39,                     // widget palette changed
        Clipboard = 40,                         // internal clipboard event
        Speech = 42,                            // reserved for speech input
        MetaCall =  43,                         // meta call event
        SockAct = 50,                           // socket activation
        WinEventAct = 132,                      // win event activation
        DeferredDelete = 52,                    // deferred delete event
        DragEnter = 60,                         // drag moves into widget
        DragMove = 61,                          // drag moves in widget
        DragLeave = 62,                         // drag leaves or is cancelled
        Drop = 63,                              // actual drop
        DragResponse = 64,                      // drag accepted/rejected
        ChildAdded = 68,                        // new child widget
        ChildPolished = 69,                     // polished child widget
        ChildRemoved = 71,                      // deleted child widget
        ShowWindowRequest = 73,                 // widget's window should be mapped
        PolishRequest = 74,                     // widget should be polished
        Polish = 75,                            // widget is polished
        LayoutRequest = 76,                     // widget should be relayouted
        UpdateRequest = 77,                     // widget should be repainted
        UpdateLater = 78,                       // request update() later

        EmbeddingControl = 79,                  // ActiveX embedding
        ActivateControl = 80,                   // ActiveX activation
        DeactivateControl = 81,                 // ActiveX deactivation
        ContextMenu = 82,                       // context popup menu
        InputMethod = 83,                       // input method
        TabletMove = 87,                        // Wacom tablet event
        LocaleChange = 88,                      // the system locale changed
        LanguageChange = 89,                    // the application language changed
        LayoutDirectionChange = 90,             // the layout direction changed
        Style = 91,                             // internal style event
        TabletPress = 92,                       // tablet press
        TabletRelease = 93,                     // tablet release
        OkRequest = 94,                         // CE (Ok) button pressed
        HelpRequest = 95,                       // CE (?)  button pressed

        IconDrag = 96,                          // proxy icon dragged

        FontChange = 97,                        // font has changed
        EnabledChange = 98,                     // enabled state has changed
        ActivationChange = 99,                  // window activation has changed
        StyleChange = 100,                      // style has changed
        IconTextChange = 101,                   // icon text has changed.  Deprecated.
        ModifiedChange = 102,                   // modified state has changed
        MouseTrackingChange = 109,              // mouse tracking state has changed

        WindowBlocked = 103,                    // window is about to be blocked modally
        WindowUnblocked = 104,                  // windows modal blocking has ended
        WindowStateChange = 105,

        ReadOnlyChange = 106,                   // readonly state has changed

        ToolTip = 110,
        WhatsThis = 111,
        StatusTip = 112,

        ActionChanged = 113,
        ActionAdded = 114,
        ActionRemoved = 115,

        FileOpen = 116,                         // file open request

        Shortcut = 117,                         // shortcut triggered
        ShortcutOverride = 51,                  // shortcut override request

        WhatsThisClicked = 118,

        ToolBarChange = 120,                    // toolbar visibility toggled

        ApplicationActivate = 121,              // deprecated. Use ApplicationStateChange instead.
        ApplicationActivated = ApplicationActivate, // deprecated
        ApplicationDeactivate = 122,            // deprecated. Use ApplicationStateChange instead.
        ApplicationDeactivated = ApplicationDeactivate, // deprecated

        QueryWhatsThis = 123,                   // query what's this widget help
        EnterWhatsThisMode = 124,
        LeaveWhatsThisMode = 125,

        ZOrderChange = 126,                     // child widget has had its z-order changed

        HoverEnter = 127,                       // mouse cursor enters a hover widget
        HoverLeave = 128,                       // mouse cursor leaves a hover widget
        HoverMove = 129,                        // mouse cursor move inside a hover widget

        // last event id used = 132

#ifdef QT_KEYPAD_NAVIGATION
        EnterEditFocus = 150,                   // enter edit mode in keypad navigation
        LeaveEditFocus = 151,                   // enter edit mode in keypad navigation
#endif
        AcceptDropsChange = 152,

        ZeroTimerEvent = 154,                   // Used for Windows Zero timer events

        GraphicsSceneMouseMove = 155,           // GraphicsView
        GraphicsSceneMousePress = 156,
        GraphicsSceneMouseRelease = 157,
        GraphicsSceneMouseDoubleClick = 158,
        GraphicsSceneContextMenu = 159,
        GraphicsSceneHoverEnter = 160,
        GraphicsSceneHoverMove = 161,
        GraphicsSceneHoverLeave = 162,
        GraphicsSceneHelp = 163,
        GraphicsSceneDragEnter = 164,
        GraphicsSceneDragMove = 165,
        GraphicsSceneDragLeave = 166,
        GraphicsSceneDrop = 167,
        GraphicsSceneWheel = 168,
        GraphicsSceneLeave = 220,

        KeyboardLayoutChange = 169,             // keyboard layout changed

        DynamicPropertyChange = 170,            // A dynamic property was changed through setProperty/property

        TabletEnterProximity = 171,
        TabletLeaveProximity = 172,

        NonClientAreaMouseMove = 173,
        NonClientAreaMouseButtonPress = 174,
        NonClientAreaMouseButtonRelease = 175,
        NonClientAreaMouseButtonDblClick = 176,

        MacSizeChange = 177,                    // when the Qt::WA_Mac{Normal,Small,Mini}Size changes

        ContentsRectChange = 178,               // sent by QWidget::setContentsMargins (internal)

        MacGLWindowChange = 179,                // Internal! the window of the GLWidget has changed

        FutureCallOut = 180,

        GraphicsSceneResize  = 181,
        GraphicsSceneMove  = 182,

        CursorChange = 183,
        ToolTipChange = 184,

        NetworkReplyUpdated = 185,              // Internal for QNetworkReply

        GrabMouse = 186,
        UngrabMouse = 187,
        GrabKeyboard = 188,
        UngrabKeyboard = 189,

        StateMachineSignal = 192,
        StateMachineWrapped = 193,

        TouchBegin = 194,
        TouchUpdate = 195,
        TouchEnd = 196,

#ifndef QT_NO_GESTURES
        NativeGesture = 197,                    // QtGui native gesture
#endif
        RequestSoftwareInputPanel = 199,
        CloseSoftwareInputPanel = 200,

        WinIdChange = 203,
#ifndef QT_NO_GESTURES
        Gesture = 198,
        GestureOverride = 202,
#endif
        ScrollPrepare = 204,
        Scroll = 205,

        Expose = 206,

        InputMethodQuery = 207,
        OrientationChange = 208,                // Screen orientation has changed

        TouchCancel = 209,

        ThemeChange = 210,

        SockClose = 211,                        // socket closed

        PlatformPanel = 212,

        StyleAnimationUpdate = 213,             // style animation target should be updated
        ApplicationStateChange = 214,

        WindowChangeInternal = 215,             // internal for QQuickWidget and texture-based widgets
        ScreenChangeInternal = 216,

        PlatformSurface = 217,                  // Platform surface created or about to be destroyed

        Pointer = 218,                          // Qt 5: QQuickPointerEvent; Qt 6: unused so far

        TabletTrackingChange = 219,             // tablet tracking state has changed

        // GraphicsSceneLeave = 220,
        WindowAboutToChangeInternal = 221,      // internal for QQuickWidget and texture-based widgets

        DevicePixelRatioChange = 222,

        // 512 reserved for Qt Jambi's MetaCall event
        // 513 reserved for Qt Jambi's DeleteOnMainThread event

        User = 1000,                            // first user event id
        MaxUser = 65535                         // last user event id
    };
    Q_ENUM(Type)

5. 事件的自定义

Qt 允许开发者自定义事件类型。自定义事件需要继承 QEvent 类,并定义自己的事件类型。例如:

#ifndef QCUSTOMEVENT_H
#define QCUSTOMEVENT_H

#include <QObject>
#include<QEvent>

class QCustomEvent : public QEvent
{
    Q_OBJECT
public:
    explicit QCustomEvent();
    ~QCustomEvent();

    static const QEvent::Type EventType = static_cast<QEvent::Type>(QEvent::User + 1);

signals:
};

#endif // QCUSTOMEVENT_H

自定义事件可以通过 QCoreApplication::postEvent()QCoreApplication::sendEvent() 发送。

6. 事件的发送方式

Qt 提供了两种发送事件的方式:

  1. QCoreApplication::sendEvent():同步发送事件,事件会立即被处理,函数返回事件的处理结果。
  2. QCoreApplication::postEvent():异步发送事件,事件会被放入事件队列中,稍后由事件循环处理。

7. 事件循环(Event Loop)

事件循环是 Qt 事件模型的核心,负责从事件队列中取出事件并分发给目标对象。事件循环通过调用 exec() 函数启动,通常在应用程序的主函数中启动:

int main(int argc, char* argv[]) {
    QApplication app(argc, argv);
    MainWindow w;
    w.show();
    return app.exec(); // 启动事件循环
}

事件循环会不断从事件队列中取出事件,并调用目标对象的事件处理器进行处理。

8. 总结

Qt 的事件模型是一个高效且灵活的机制,通过事件的产生、传递和处理,实现了用户交互和系统事件的响应。开发者可以通过重写事件处理器、安装事件过滤器或自定义事件类型,灵活地扩展和定制 Qt 应用程序的行为。


http://www.kler.cn/a/568487.html

相关文章:

  • 【AI绘画】黑白木刻之希腊神话系列(一丹一世界)
  • MYSQL增删改查操作
  • 策略模式环境类的实现方式对比
  • 优博讯,蓝禾,三七互娱,顺丰,oppo,游卡,汤臣倍健,康冠科技,作业帮,高途教育25届春招内推
  • Spring Security 如何防止 CSRF 攻击?
  • Redis数据结构-List列表
  • 10.3 指针进阶_代码分析
  • 自学微信小程序的第七天
  • hive之LEAD 函数详解
  • 【重构小程序】升级JDK1.8、SpringBoot2.x 到JDK17、Springboot 3.x(一)
  • 算法刷题-2025年02月26日
  • JMeter 实战项目脚本录制最佳实践(含 BadBoy 录制方式)
  • 【Maven】基于IDEA进行Maven工程的创建、构建
  • 【前端场景面试】登录鉴权实现方式详解
  • 《论软件测试中缺陷管理及其应用》审题技巧 - 系统架构设计师
  • 【C++/数据结构】队列
  • uni-app 全局请求封装:支持 Promise,自动刷新 Token,解决 401 过期问题
  • 【数据结构】堆与二叉树
  • 基于SpringBoot和Leaflet的行政区划地图掩膜效果实战
  • 人工智能领域顶级期刊