Qt消息事件的处理逻辑与执行流程
1. 事件的概念
事件是程序中发生的一些特定操作或状态的改变,比如鼠标点击、键盘输入、窗口调整大小、定时器超时等
2. 事件的处理机制
事件的处理机制包括事件的生成、分发和处理。以下是详细的处理逻辑和执行流程:
2.1. 事件的生成
当一个事件发生时,会创建一个事件对象并将其加入到主线程的事件队列中。事件可以来自多种来源,例如操作系统、网络或应用程序内部。
在Windows环境下,由窗口的回调函数qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
将widnows消息翻译成Qt的QEvent
事件,函数的处理逻辑可以分为以下几个步骤:
消息类型转换:将Windows消息类型转换为Qt内部的
WindowsEventType
枚举值。这一步通过windowsEventType
函数完成。const QtWindows::WindowsEventType et = windowsEventType(message, wParam, lParam);
调用
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; }
处理结果:如果
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!");
}
}
};