Qt消息事件的处理逻辑与执行流程

1. 事件的概念

事件是程序中发生的一些特定操作或状态的改变,比如鼠标点击、键盘输入、窗口调整大小、定时器超时等

2. 事件的处理机制

事件的处理机制包括事件的生成、分发和处理。以下是详细的处理逻辑和执行流程:

2.1. 事件的生成

当一个事件发生时,会创建一个事件对象并将其加入到主线程的事件队列中。事件可以来自多种来源,例如操作系统、网络或应用程序内部。

在Windows环境下,由窗口的回调函数qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)将widnows消息翻译成Qt的QEvent事件,函数的处理逻辑可以分为以下几个步骤:

  1. 消息类型转换:将Windows消息类型转换为Qt内部的WindowsEventType 枚举值。这一步通过 windowsEventType 函数完成。

    const QtWindows::WindowsEventType et = windowsEventType(message, wParam, lParam);
    
  2. 调用QWindowsContext::windowsProc该函数是 Qt 内部用于处理 Windows 消息的函数。它会根据消息类型调用相应的处理函数。

    const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result);
    

    QWindowsContext::windowsProc 函数会根据不同的消息类型调用不同的处理函数。例如,对于鼠标事件,会调用 QWindowsMouseHandler::translateMouseEvent

    case QtWindows::MouseEvent:
    case QtWindows::MouseWheelEvent:
    case QtWindows::LeaveEvent:
        {
            QWindow *window = platformWindow->window();
            while (window && (window->flags() & Qt::WindowTransparentForInput))
                window = window->parent();
            if (!window)
                return false;
            if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
                return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(window, hwnd, et, msg, result);
            else
                return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
        }
        break;
    

    QWindowsMouseHandler::translateMouseEvent 函数将 Windows 的鼠标消息转换为 Qt 的 WindowSystemEvent,并将其放入 Qt 的事件队列中。

    bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) {
        // 处理鼠标事件,转换为 QMouseEvent
        if (!discardEvent && mouseEvent.type != QEvent::None) {
            QWindowSystemInterface::handleMouseEvent(window, device, clientPosition, globalPosition, buttons, mouseEvent.button, mouseEvent.type, keyModifiers, source);
        }
        return true;
    }
    

    转换后的事件会被放入 QWindowSystemInterfacePrivate 的全局系统事件队列中。事件循环会从这个队列中取出事件并分发给相应的对象。

    void QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags) {
        while (QWindowSystemInterfacePrivate::windowSystemEventsQueued()) {
            QWindowSystemInterfacePrivate::WindowSystemEvent *event = QWindowSystemInterfacePrivate::getWindowSystemEvent();
            if (!event)
                break;
            if (QWindowSystemInterfacePrivate::eventHandler) {
                if (QWindowSystemInterfacePrivate::eventHandler->sendEvent(event))
                    nevents++;
            } else {
                nevents++;
                QGuiApplicationPrivate::processWindowSystemEvent(event);
            }
            delete event;
        }
    }
    

    最终,事件会被分发到目标对象的 event() 方法中,目标对象可以重写 event() 方法或特定的事件处理方法(如 mousePressEvent)来处理事件。

    bool QWidget::event(QEvent *event) {
        switch (event->type()) {
        case QEvent::MouseButtonPress:
            mousePressEvent(static_cast<QMouseEvent *>(event));
            break;
        // 其他事件类型
        default:
            return QObject::event(event);
        }
        return true;
    }
    
  3. 处理结果:如果QWindowsContext::windowsProc 处理了消息,返回处理结果,否则调用 DefWindowProc 以确保消息被默认处理。

    if (!handled)
            result = DefWindowProc(hwnd, message, wParam, lParam);
    return result;
    

2.2. 事件的循环处理

事件循环是一个无限循环,它从操作系统或其它事件源获取事件,并将其分发给应用程序中的对象进行处理,直到app退出。

2.3. 事件的分发

事件循环事件从事件队列这种取出事件,并将其分发给目标对象。事件处理包括以下几个步骤:

  • 事件过滤器:事件首先将其传递给事件过滤器,事件过滤器可以选择处理事件或者将其传递给下一个处理器。

      class MyEventFilter : public QObject {
      protected:
         bool eventFilter(QObject *obj, QEvent *event) override {
             if (event->type() == QEvent::User) {
                 // 处理自定义事件
                 return true; // 事件已处理
             }
             return QObject::eventFilter(obj, event); // 传递给父类处理
         }
      };
    
  • 事件处理器:如果事件没有被事件过滤器处理,Qt会调用目标对象的event()event()方法会根据事件类型调用特定的事件处理器方法,mouseEvent()keyPressEvent()等。

      class MyObject : public QObject {
      protected:
         bool event(QEvent *event) override {
             if (event->type() == QEvent::User) {
                 // 处理自定义事件
                 return true; // 事件已处理
             }
             return QObject::event(event); // 传递给父类处理
         }
         void mousePressEvent(QMouseEvent *event) override {
             // 处理鼠标按下事件
         }
         void keyPressEvent(QKeyEvent *event) override {
             // 处理键盘按下事件
         }
      };
    

2.4. 事件的响应

相关的事件处理函数(如mousePressEvent())被调用,执行具体的处理逻辑。例如鼠标点击事件:

class MyButton : public QPushButton {
public:
    using QPushButton::QPushButton; // 继承构造函数
protected:
    void mousePressEvent(QMouseEvent *event) override {
        if (event->button() == Qt::LeftButton) {
            QMessageBox::information(this, "Clicked", "Button Clicked!");
        }
    }
};

results matching ""

    No results matching ""