QEvent和它的涉及类继承体系和设计思想
目录
1.QEvent
1.1.简介
1.2.QEvent 核心接口与状态
1.3.事件类型(QEvent::Type)
1.4.事件处理流程
1.5.自定义事件
1.6.关键注意事项
2.QEvent 类继承体系
3.QEvent 设计思想
4.总结
1.QEvent
1.1.简介
QEvent
是 Qt 事件驱动模型的核心类,封装了所有与事件相关的信息(如用户交互、系统通知、自定义行为等),并提供了事件识别、传递和处理的基础接口。
QEvent
是 Qt 中所有事件的抽象基类,任何事件(如鼠标点击、窗口刷新、定时器超时)都必须继承自它。
它的特征有:
- 每个事件有唯一的类型标识(
QEvent::Type
); - 支持事件的 “接受 / 忽略” 状态(控制事件是否继续传递);
- 兼容 Qt 元对象系统,支持跨线程事件传递。
QT 中的元对象系统(二):元对象实现原理QMetaObject
1.2.QEvent 核心接口与状态
QEvent
提供了基础接口用于事件识别和状态管理,类定义如下:
class QEventPrivate;
class Q_CORE_EXPORT QEvent // event base class
{Q_GADGETQDOC_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public: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 afterthe Qt includes to solve this problem.*/None = 0, // invalid eventTimer = 1, // timer eventMouseButtonPress = 2, // mouse button pressedMouseButtonRelease = 3, // mouse button releasedMouseButtonDblClick = 4, // mouse button double clickMouseMove = 5, // mouse moveKeyPress = 6, // key pressedKeyRelease = 7, // key releasedFocusIn = 8, // keyboard focus receivedFocusOut = 9, // keyboard focus lostFocusAboutToChange = 23, // keyboard focus is about to be lostEnter = 10, // mouse enters widgetLeave = 11, // mouse leaves widgetPaint = 12, // paint widgetMove = 13, // move widgetResize = 14, // resize widgetCreate = 15, // after widget creationDestroy = 16, // during widget destructionShow = 17, // widget is shownHide = 18, // widget is hiddenClose = 19, // request to close widgetQuit = 20, // request to quit applicationParentChange = 21, // widget has been reparentedParentAboutToChange = 131, // sent just before the parent change is doneThreadChange = 22, // object has changed threadsWindowActivate = 24, // window was activatedWindowDeactivate = 25, // window was deactivatedShowToParent = 26, // widget is shown to parentHideToParent = 27, // widget is hidden to parentWheel = 31, // wheel eventWindowTitleChange = 33, // window title changedWindowIconChange = 34, // icon changedApplicationWindowIconChange = 35, // application icon changedApplicationFontChange = 36, // application font changedApplicationLayoutDirectionChange = 37, // application layout direction changedApplicationPaletteChange = 38, // application palette changedPaletteChange = 39, // widget palette changedClipboard = 40, // internal clipboard eventSpeech = 42, // reserved for speech inputMetaCall = 43, // meta call eventSockAct = 50, // socket activationWinEventAct = 132, // win event activationDeferredDelete = 52, // deferred delete eventDragEnter = 60, // drag moves into widgetDragMove = 61, // drag moves in widgetDragLeave = 62, // drag leaves or is cancelledDrop = 63, // actual dropDragResponse = 64, // drag accepted/rejectedChildAdded = 68, // new child widgetChildPolished = 69, // polished child widgetChildRemoved = 71, // deleted child widgetShowWindowRequest = 73, // widget's window should be mappedPolishRequest = 74, // widget should be polishedPolish = 75, // widget is polishedLayoutRequest = 76, // widget should be relayoutedUpdateRequest = 77, // widget should be repaintedUpdateLater = 78, // request update() laterEmbeddingControl = 79, // ActiveX embeddingActivateControl = 80, // ActiveX activationDeactivateControl = 81, // ActiveX deactivationContextMenu = 82, // context popup menuInputMethod = 83, // input methodTabletMove = 87, // Wacom tablet eventLocaleChange = 88, // the system locale changedLanguageChange = 89, // the application language changedLayoutDirectionChange = 90, // the layout direction changedStyle = 91, // internal style eventTabletPress = 92, // tablet pressTabletRelease = 93, // tablet releaseOkRequest = 94, // CE (Ok) button pressedHelpRequest = 95, // CE (?) button pressedIconDrag = 96, // proxy icon draggedFontChange = 97, // font has changedEnabledChange = 98, // enabled state has changedActivationChange = 99, // window activation has changedStyleChange = 100, // style has changedIconTextChange = 101, // icon text has changed. Deprecated.ModifiedChange = 102, // modified state has changedMouseTrackingChange = 109, // mouse tracking state has changedWindowBlocked = 103, // window is about to be blocked modallyWindowUnblocked = 104, // windows modal blocking has endedWindowStateChange = 105,ReadOnlyChange = 106, // readonly state has changedToolTip = 110,WhatsThis = 111,StatusTip = 112,ActionChanged = 113,ActionAdded = 114,ActionRemoved = 115,FileOpen = 116, // file open requestShortcut = 117, // shortcut triggeredShortcutOverride = 51, // shortcut override requestWhatsThisClicked = 118,ToolBarChange = 120, // toolbar visibility toggledApplicationActivate = 121, // deprecated. Use ApplicationStateChange instead.ApplicationActivated = ApplicationActivate, // deprecatedApplicationDeactivate = 122, // deprecated. Use ApplicationStateChange instead.ApplicationDeactivated = ApplicationDeactivate, // deprecatedQueryWhatsThis = 123, // query what's this widget helpEnterWhatsThisMode = 124,LeaveWhatsThisMode = 125,ZOrderChange = 126, // child widget has had its z-order changedHoverEnter = 127, // mouse cursor enters a hover widgetHoverLeave = 128, // mouse cursor leaves a hover widgetHoverMove = 129, // mouse cursor move inside a hover widget// last event id used = 132#ifdef QT_KEYPAD_NAVIGATIONEnterEditFocus = 150, // enter edit mode in keypad navigationLeaveEditFocus = 151, // enter edit mode in keypad navigation
#endifAcceptDropsChange = 152,ZeroTimerEvent = 154, // Used for Windows Zero timer eventsGraphicsSceneMouseMove = 155, // GraphicsViewGraphicsSceneMousePress = 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,KeyboardLayoutChange = 169, // keyboard layout changedDynamicPropertyChange = 170, // A dynamic property was changed through setProperty/propertyTabletEnterProximity = 171,TabletLeaveProximity = 172,NonClientAreaMouseMove = 173,NonClientAreaMouseButtonPress = 174,NonClientAreaMouseButtonRelease = 175,NonClientAreaMouseButtonDblClick = 176,MacSizeChange = 177, // when the Qt::WA_Mac{Normal,Small,Mini}Size changesContentsRectChange = 178, // sent by QWidget::setContentsMargins (internal)MacGLWindowChange = 179, // Internal! the window of the GLWidget has changedFutureCallOut = 180,GraphicsSceneResize = 181,GraphicsSceneMove = 182,CursorChange = 183,ToolTipChange = 184,NetworkReplyUpdated = 185, // Internal for QNetworkReplyGrabMouse = 186,UngrabMouse = 187,GrabKeyboard = 188,UngrabKeyboard = 189,MacGLClearDrawable = 191, // Internal Cocoa, the window has changed, so we must clearStateMachineSignal = 192,StateMachineWrapped = 193,TouchBegin = 194,TouchUpdate = 195,TouchEnd = 196,#ifndef QT_NO_GESTURESNativeGesture = 197, // QtGui native gesture
#endifRequestSoftwareInputPanel = 199,CloseSoftwareInputPanel = 200,WinIdChange = 203,
#ifndef QT_NO_GESTURESGesture = 198,GestureOverride = 202,
#endifScrollPrepare = 204,Scroll = 205,Expose = 206,InputMethodQuery = 207,OrientationChange = 208, // Screen orientation has changedTouchCancel = 209,ThemeChange = 210,SockClose = 211, // socket closedPlatformPanel = 212,StyleAnimationUpdate = 213, // style animation target should be updatedApplicationStateChange = 214,WindowChangeInternal = 215, // internal for QQuickWidgetScreenChangeInternal = 216,PlatformSurface = 217, // Platform surface created or about to be destroyedPointer = 218, // QQuickPointerEvent; ### Qt 6: QPointerEventTabletTrackingChange = 219, // tablet tracking state has changed// 512 reserved for Qt Jambi's MetaCall event// 513 reserved for Qt Jambi's DeleteOnMainThread eventUser = 1000, // first user event idMaxUser = 65535 // last user event id};Q_ENUM(Type)explicit QEvent(Type type);QEvent(const QEvent &other);virtual ~QEvent();QEvent &operator=(const QEvent &other);inline Type type() const { return static_cast<Type>(t); }inline bool spontaneous() const { return spont; }inline void setAccepted(bool accepted) { m_accept = accepted; }inline bool isAccepted() const { return m_accept; }inline void accept() { m_accept = true; }inline void ignore() { m_accept = false; }static int registerEventType(int hint = -1) Q_DECL_NOTHROW;protected:QEventPrivate *d;ushort t;private:ushort posted : 1;ushort spont : 1;ushort m_accept : 1;ushort reserved : 13;friend class QCoreApplication;friend class QCoreApplicationPrivate;friend class QThreadData;friend class QApplication;friend class QShortcutMap;friend class QGraphicsView;friend class QGraphicsScene;friend class QGraphicsScenePrivate;// from QtTest:friend class QSpontaneKeyEvent;// needs this:Q_ALWAYS_INLINEvoid setSpontaneous() { spont = true; }
};
核心成员如下:
接口 / 成员 | 功能描述 |
---|---|
QEvent::Type type() | 返回事件类型(枚举值),用于识别事件(如 QEvent::MouseButtonPress 表示鼠标按下)。 |
void accept() | 标记事件为 “已处理”,事件将停止向上传递(父对象不再接收该事件)。 |
void ignore() | 标记事件为 “未处理”,事件将继续向上传递给父对象(父对象可能处理该事件)。 |
bool isAccepted() | 判断事件是否被接受(accept() 后返回 true ,ignore() 后返回 false )。 |
bool spontaneous() | 判断事件是否为 “自发事件”:true 表示由系统 / 用户触发(如鼠标点击),false 表示由程序手动发送(如 postEvent )。 |
1.3.事件类型(QEvent::Type)
Qt 预定义了数百种事件类型(QEvent::Type
枚举),覆盖各类场景,按功能可分为以下几类(常用类型示例):
1.输入事件(用户交互)
QEvent::MouseButtonPress
:鼠标按键按下(左键 / 右键等);QEvent::MouseButtonRelease
:鼠标按键释放;QEvent::MouseMove
:鼠标移动;QEvent::Wheel
:鼠标滚轮滚动;QEvent::KeyPress
:键盘按键按下;QEvent::KeyRelease
:键盘按键释放;QEvent::TouchBegin
/TouchUpdate
/TouchEnd
:触摸事件(移动设备)。
2.窗口与控件事件
QEvent::Show
:窗口 / 控件显示;QEvent::Hide
:窗口 / 控件隐藏;QEvent::Resize
:窗口 / 控件大小改变;QEvent::Move
:窗口 / 控件位置移动;QEvent::Close
:窗口关闭请求;QFocusIn
/QFocusOut
:控件获得 / 失去焦点;QEvent::Enter
/QEvent::Leave
:鼠标进入 / 离开控件区域。
3.绘制与刷新事件
QEvent::Paint
:控件需要重绘(触发paintEvent()
);QEvent::UpdateRequest
:请求更新控件(通常由update()
触发,用于延迟重绘)。
4.定时器与网络事件
QEvent::Timer
:定时器超时(触发timerEvent()
);QEvent::NetworkReplyFinished
:网络请求完成(QtNetwork 模块);QEvent::SocketActivated
:套接字活动(如收到数据)。
5.自定义事件范围
Qt 预留了 QEvent::User
(1000
)到 QEvent::MaxUser
(65535
)的范围用于自定义事件,避免与系统事件冲突。需通过 QEvent::registerEventType()
注册(见后文)。
1.4.事件处理流程
Qt 事件从产生到处理需经过事件产生→事件分发→事件过滤→事件处理→事件传递五个阶段,流程如下:
1.事件产生
- 系统事件:由操作系统或硬件触发(如用户点击鼠标→系统生成鼠标事件→Qt 捕获并封装为
QMouseEvent
); - 程序事件:由 Qt 或用户代码生成(如
QTimer
超时生成QTimerEvent
,用户调用postEvent
发送自定义事件)。
2.事件分发(QApplication::notify ())
事件产生后,由 QApplication
(或 QCoreApplication
)的 notify()
函数统一分发:
bool QApplication::notify(QObject *receiver, QEvent *e) {// 1. 检查是否有事件过滤器拦截该事件if (filterEvent(receiver, e)) return true;// 2. 调用接收者的 event() 函数处理事件return receiver->event(e);
}
notify()
是事件分发的入口,确保每个事件被正确传递到目标对象(receiver
)。
3.事件过滤(installEventFilter ())
在事件到达目标对象前,可被 “事件过滤器” 拦截处理:
- 过滤器通过
QObject::installEventFilter(QObject *filter)
安装到目标对象; - 过滤器需重写
eventFilter(QObject *watched, QEvent *e)
,返回true
表示拦截事件(不再传递),false
表示放行。
示例:拦截按钮的鼠标点击事件
class Filter : public QObject {
protected:bool eventFilter(QObject *watched, QEvent *e) override {// 若目标是按钮且事件是鼠标按下,则拦截if (watched == ui->pushButton && e->type() == QEvent::MouseButtonPress) {qDebug() << "拦截按钮点击";return true; // 拦截事件}return false; // 放行其他事件}
};// 使用:为按钮安装过滤器
Filter *filter = new Filter;
ui->pushButton->installEventFilter(filter);
4.事件处理(event () 与特定事件函数)
事件到达目标对象后,通过以下两种方式处理:
1) 方式 1:重写 event()
函数(通用事件处理入口):
目标对象(如 QWidget
)的 event()
函数根据事件类型,分发到具体的事件处理函数(如 mousePressEvent
)。用户可重写 event()
实现自定义分发逻辑:
bool MyWidget::event(QEvent *e) override {if (e->type() == QEvent::MouseButtonPress) {qDebug() << "处理鼠标按下事件(event())";return true; // 处理完成}// 未处理的事件交给父类return QWidget::event(e);
}
2) 方式 2:重写特定事件函数(便捷处理):
Qt 控件已将常见事件封装为虚函数(如 mousePressEvent
、keyPressEvent
、paintEvent
),直接重写即可:
void MyWidget::mousePressEvent(QMouseEvent *e) override {qDebug() << "鼠标按下位置:" << e->pos();// 若需让父类继续处理(如保持默认行为),调用父类实现QWidget::mousePressEvent(e);
}
5.事件传递(接受 / 忽略机制)
若事件未被处理(或调用了 ignore()
),会向上传递给父对象,直到被处理或到达顶级窗口:
- 调用
e->accept()
:事件停止传递(默认行为,多数事件处理函数会自动接受); - 调用
e->ignore()
:事件继续传递给父对象。
示例:子控件忽略事件,让父控件处理
void ChildWidget::mousePressEvent(QMouseEvent *e) {e->ignore(); // 忽略事件,让父控件处理
}void ParentWidget::mousePressEvent(QMouseEvent *e) {qDebug() << "父控件处理子控件未处理的鼠标事件";
}
1.5.自定义事件
当预定义事件满足不了需求(如业务逻辑事件),可通过以下步骤实现自定义事件
1.注册自定义事件类型
使用 QEvent::registerEventType()
分配唯一类型值(避免冲突):
// 注册自定义事件类型(通常在程序初始化时)
const QEvent::Type MyEventType = static_cast<QEvent::Type>(QEvent::registerEventType());
2.定义自定义事件类
继承 QEvent
,封装业务数据:
class MyEvent : public QEvent {
public:MyEvent(int data) : QEvent(MyEventType), m_data(data) {}int data() const { return m_data; } // 自定义数据访问接口
private:int m_data; // 业务数据
};
3.发送自定义事件
通过 sendEvent
(同步)或 postEvent
(异步)发送:
// 同步发送:事件立即处理,阻塞当前线程
MyEvent event(123);
QCoreApplication::sendEvent(targetObject, &event);// 异步发送:事件加入队列,由事件循环处理(非阻塞)
// 注意:postEvent 需动态分配事件对象(Qt 会自动释放)
QCoreApplication::postEvent(targetObject, new MyEvent(123));
4.处理自定义事件
在目标对象中重写 event()
或使用事件过滤器:
bool MyObject::event(QEvent *e) override {if (e->type() == MyEventType) {MyEvent *myEvent = static_cast<MyEvent*>(e);qDebug() << "收到自定义事件,数据:" << myEvent->data();return true;}return QObject::event(e);
}
1.6.关键注意事项
1.线程安全性
- 事件可跨线程传递(通过
postEvent
),Qt 会自动将事件放入目标线程的事件队列; - 自定义事件的
data
若包含指针,需确保线程安全(如使用QSharedPointer
)。
2.事件与信号槽的区别
- 事件是 “被动通知”(由系统或框架触发),信号槽是 “主动通信”(由对象主动发射);
- 事件支持传递和过滤,信号槽一旦连接直接触发。
3.性能考量
- 高频事件(如鼠标移动)需轻量化处理,避免阻塞事件循环;
- 大量自定义事件建议批量发送,减少事件队列压力。
4.事件处理函数的默认行为
重写事件函数时,若需保留控件默认行为(如按钮点击的视觉反馈),需调用父类实现(如 QPushButton::mousePressEvent(e)
)。
2.QEvent 类继承体系
QEvent
是 Qt 事件系统的根类,所有具体事件(如鼠标点击、窗口刷新)均派生自它。其继承体系按 “事件类型” 分层,核心子类可分为输入事件、窗口事件、绘制事件、定时器事件、自定义事件等,形成清晰的分类结构。
1.输入事件(用户交互相关)
基类为 QInputEvent
,封装输入设备(鼠标、键盘、触摸等)的事件信息:
QInputEvent
:输入事件基类,包含事件发生的时间戳(timestamp()
)和修饰键状态(modifiers()
,如 Ctrl、Shift 键是否按下)。QMouseEvent
:鼠标事件(点击、移动、释放等),提供坐标(x()
/y()
)、鼠标按钮(button()
)、点击次数(clickCount()
)等信息,子类包括QMousePressEvent
(按下)、QMouseReleaseEvent
(释放)、QMouseMoveEvent
(移动)等。QWheelEvent
:鼠标滚轮事件,提供滚轮滚动方向和角度(delta()
)、滚轮坐标等。QKeyEvent
:键盘事件(按键按下 / 释放),提供键值(key()
,如Qt::Key_A
)、字符(text()
,如按下 Shift+A 时为A
)等。QTouchEvent
:触摸事件(多点触摸),包含触摸点列表(touchPoints()
),支持移动设备交互。
2.窗口与控件事件(UI 状态变化)
处理窗口或控件的状态变化(如大小、显示 / 隐藏、焦点等):
QWindowEvent
:窗口状态事件,如窗口关闭(QEvent::Close
)、显示(QEvent::Show
)、隐藏(QEvent::Hide
)、移动(QEvent::Move
)、大小变化(QEvent::Resize
)等。QFocusEvent
:焦点事件(控件获得 / 失去焦点),包含焦点原因(reason()
,如用户点击、Tab 键切换)。QEnterEvent
/QLeaveEvent
:鼠标进入 / 离开控件区域的事件(用于悬停效果)。
3.绘制与刷新事件
触发控件重绘的事件:
QPaintEvent
:绘制事件,当控件需要重绘(如首次显示、被遮挡后恢复)时触发,包含需要重绘的区域(rect()
),控件通过重写paintEvent()
实现自定义绘制。
4.定时器与网络事件
QTimerEvent
:定时器事件,当QTimer
超时或调用startTimer()
后,定时触发,包含定时器 ID(timerId()
)用于区分多个定时器。QNetworkEvent
(Qt Network 模块):网络事件(如数据接收、连接状态变化),基类为QEvent
,具体子类如QNetworkReply::finished
相关事件(封装在 Qt 网络框架内部)。
5.自定义事件
用户可通过继承 QEvent
实现自定义事件,需使用 QEvent::User
到 QEvent::MaxUser
范围内的类型(避免与系统事件冲突)。
3.QEvent 设计思想
Qt 事件系统的设计围绕 “灵活的事件分发与处理” 展开,核心思想包括:
1.事件封装:面向对象的事件表示
- 每个事件(如鼠标点击、窗口关闭)被封装为一个
QEvent
子类对象,包含该事件的所有相关信息(如鼠标事件的坐标、键盘事件的键值)。 - 这种封装使得事件的传递、存储、处理可以统一通过对象接口完成,符合面向对象的 “信息隐藏” 原则(事件的具体细节由子类内部实现,外部通过接口访问)。
2.事件类型识别:多态与类型判断
- 所有事件通过
QEvent::type()
标识类型,配合dynamic_cast
可将基类QEvent*
转换为具体子类(如QMouseEvent*
),实现多态处理:
bool MyWidget::event(QEvent *e) {if (e->type() == QEvent::MouseButtonPress) {// 转换为具体事件类型,获取详细信息QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);qDebug() << "鼠标按下位置:" << mouseEvent->pos();return true; // 标记事件已处理}return QWidget::event(e); // 未处理的事件交给父类
}
- 这种设计允许一个统一的接口(
event()
)处理所有类型的事件,具体逻辑由事件类型动态决定,体现 “开闭原则”(新增事件类型无需修改现有处理框架)。
3.事件传递:层次化分发与冒泡机制
- 事件产生后,Qt 会通过
QApplication::notify()
按 “层次化路径” 分发:从底层窗口(如子控件)向上传递到父窗口,直至顶级窗口或被处理。 - 例如,点击一个按钮时,事件先传递给按钮,若按钮未处理(
ignore()
),则传递给按钮的父控件(如QWidget
),以此类推。这种 “冒泡机制” 允许父组件拦截子组件未处理的事件,增加处理灵活性。
4.事件过滤:拦截与监控机制
Qt 提供 installEventFilter()
允许一个对象(过滤器)监控另一个对象的事件,在事件到达目标对象前先由过滤器处理:
// 过滤器对象
class MyFilter : public QObject {
protected:bool eventFilter(QObject *watched, QEvent *e) override {if (watched == targetWidget && e->type() == QEvent::MouseButtonPress) {qDebug() << "拦截到目标控件的鼠标点击";return true; // 拦截事件,不再传递}return false; // 不拦截,继续传递}
};// 使用:为目标控件安装过滤器
MyFilter *filter = new MyFilter;
targetWidget->installEventFilter(filter);
- 这种设计允许在不修改目标对象代码的前提下,扩展或监控其事件处理,体现 “组合优于继承” 的设计原则。
5.同步与异步事件:灵活的触发方式
- Qt 支持两种事件发送方式:
- 同步发送(
QCoreApplication::sendEvent()
):事件直接传递给目标对象的event()
函数,立即处理,阻塞当前线程直至完成; - 异步发送(
QCoreApplication::postEvent()
):事件被加入事件队列,由 Qt 的事件循环(QEventLoop
)异步处理,不阻塞当前线程。
- 同步发送(
- 这种区分满足了不同场景需求:同步事件用于需要立即响应的场景(如关键输入),异步事件用于非紧急任务(如批量数据更新),避免阻塞主线程。
6.扩展性:支持自定义事件
- 通过继承
QEvent
并使用User
范围内的类型,用户可定义业务相关的事件(如 “数据处理完成事件”“状态变更事件”),并通过sendEvent()
/postEvent()
发送,与系统事件统一处理。 - 这种设计使事件系统不仅能处理内置事件,还能无缝集成业务逻辑,体现 “可扩展” 特性。
4.总结
Qt 的 QEvent
继承体系通过 “基类抽象 + 子类具体实现” 的分层设计,清晰分类了各类事件(输入、窗口、绘制等),为事件识别和处理提供了统一接口。其设计思想围绕灵活的事件分发(层次化传递、过滤机制)、面向对象的封装(事件即对象)、可扩展性(自定义事件)展开,使得 Qt 能够高效处理复杂的用户交互和系统通知,同时为开发者提供了丰富的扩展点(如重写 event()
、事件过滤、自定义事件)。
这种设计是 Qt 事件驱动模型的核心,也是其界面响应灵活、可定制性强的关键原因。