ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

NodeGui 的 QObject 指南:从对象树、属性系统到事件与计时器全解析

NodeGui 的 QObject 指南:从对象树、属性系统到事件与计时器全解析 桌面应用跨平台【免费下载链接】nodeguiA library for building cross-platform native desktop applications with Node.js and CSS . React NodeGui : https://react.nodegui.org and Vue NodeGui: https://vue.nodegui.org项目地址https://gitcode.com/gh_mirrors/no/nodegui点击查看免费下载QObject 是 Qt 对象模型的基石也是 NodeGui用 Node.js CSS 构建跨平台原生桌面应用的库中几乎所有组件类的最顶层基类之一。本文以 NodeGui 仓库自动生成的 API 文档 classes/qobject.md 为骨架结合 TypeScript 封装源码与 C 原生绑定实现系统讲解 NodeGui 中QObject的构造方式、父子对象树、动态属性系统、事件/信号监听、对象标识与生命周期管理、以及计时器 API帮助读者理解并正确使用这一贯穿所有组件的核心类。QObject 在 NodeGui 类体系中的位置在 NodeGui 的 TypeScript 类体系中QObject的完整泛型签名是QObjectSignals extends QObjectSignals QObjectSignals它继承自EventWidgetSignals见 src/lib/QtCore/QObject.ts。EventWidget又继承自Component后者是所有组件与布局的最顶层基类负责持有对原生 C 实例native: NativeElement | null的引用见 src/lib/core/Component.ts。从 API 文档的 Hierarchy 一节可以看到QObject处于整棵类树的中枢位置它派生出大量常用类包括EventWidget事件基类→ 进而派生出YogaWidget、QLayout以及所有QWidget系列组件QAction、QGraphicsEffect、QClipboard、QScreen、QApplication、QMovie、QWindow模型/视图类QAbstractItemModel、QItemSelectionModel、QStandardItemModel控件类QButtonGroup、QSystemTrayIcon、QShortcut测试辅助类CacheTestQObject对应仓库中的 src/lib/core/test/CacheTestQObject.ts。在 C 侧NodeGui 用NObject继承自QObject并混入EventWidget作为所有原生对象的基类见 src/cpp/include/nodegui/QtCore/QObject/nobject.hpp并通过QObjectWrap继承自Napi::ObjectWrap持有QPointerQObject instance完成 N-API 绑定见 src/cpp/include/nodegui/QtCore/QObject/qobject_wrap.h。大量通用方法通过QOBJECT_WRAPPED_METHODS_DECLARATION宏批量导出见 src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h这也是所有 Qt 组件都能共享QObjectAPI 的原因。构造 QObject两种入参形态QObject的构造函数签名是new QObject(nativeElementOrParent?: NativeElement | QObject): QObject构造参数是可选的支持两种传法对应 src/lib/QtCore/QObject.ts 中的三种分支逻辑不传参创建一个独立的原生QObjectnew addon.QObject()没有父对象传入一个QObject把它当作父对象创建一个带父对象的新QObjectnew addon.QObject(parent.native)新对象会加入父对象的 children 列表传入NativeElement内部使用在从原生指针恢复封装时直接把原生实例包装成 JS 对象。在 C 绑定层QObjectWrap的构造函数同样区分argCount 0、argCount 1且参数是ExternalQObject、以及参数是父对象包装三种情况见 src/cpp/lib/QtCore/QObject/qobject_wrap.cpp。注意QObject本身是一个可用于测试的普通类仓库测试中直接new QObject()见 src/lib/QtCore/tests/QObject.test.ts但在真实应用中通常不需要直接实例化它——更多是创建它的子类组件如QPushButton、QWidget然后通过继承来的 API 操作对象。对象树parent / children / setParentQt 的对象树机制父子关系决定内存所有权在 NodeGui 中完整保留相关的 API 有方法签名作用parent()(): QObject返回当前对象的父对象若没有父对象则返回null封装的包装setParent(parent)(parent: QObject): void把当前对象挂到指定父对象下传null可解除父子关系children()(): QObject[]返回直接子对象的数组parent()和children()的返回都经过WrapperCache的getWrapper转换确保同一个原生QObject指针在 JS 侧始终对应同一个封装实例见 src/lib/QtCore/QObject.ts。setParent的实现比较特殊在 TypeScript 层它先通过parent.native.__external_qobject__()取出父对象的原生QObject*再传给原生setParent在 C 宏中setParent支持传入null解除父子或ExternalQObject建立父子见 src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h。父子关系会带来两条实用能力对象树诊断dumpObjectTree()在控制台打印以当前对象为根的整棵对象树dumpObjectInfo()打印当前对象的信息摘要二者直接对应 Qt 的QObject::dumpObjectTree()/dumpObjectInfo()生命周期传导父对象销毁时其子对象也会一并销毁Qt 对象树语义配合下文delete()与deleteLater()使用。对象标识与内存调试native / _id / inheritsnative 属性native: NativeElement | null继承自Component是连接 JS 世界与 C 世界的桥梁几乎所有方法都通过this.native.xxx()调用原生绑定。调试时可以直接检查native上暴露的绑定方法列表。_id()定位底层 C 对象_id(): number返回一个标识底层 C 对象的数字 ID。文档明确指出该数字是 C 对象内存地址的哈希值在 C 对象存活期内保持有效可用于配合setLogCreateQObject()/setLogDestroyQObject()调试内存问题。对应实现见 src/lib/QtCore/QObject.ts构造函数中缓存native.__id__()C 侧由宏中__id__方法通过extrautils::hashPointerTo53bit计算见 src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h。inherits()inherits(className: string): boolean用于判断当前对象是否继承自指定类名。仓库测试就用到它验证new QObject()确实inherits(QObject)见 src/lib/QtCore/tests/QObject.test.ts。它在 C 侧直接调用QObject::inherits()见 src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h。动态属性系统setProperty / propertyQt 允许在运行时给QObject动态挂载任意属性NodeGui 完整暴露了这对 APIsetProperty(name: string, value: QVariantType): boolean property(name: string): QVariant其中QVariantType是NativeElement | string | string[] | number | boolean | QRect见 src/lib/QtCore/QVariant.ts。setProperty返回boolean表示属性是否设置成功property返回一个QVariant包装对象可通过toString()、toInt()、toDouble()、toBool()、toStringList()等方法取回 JS 值见 src/lib/QtCore/QVariant.ts。C 侧setProperty先把 JS 值经extrautils::convertToQVariant转成QVariant再调用QObject::setProperty()property则把取到的QVariant包装成QVariantWrap返回见 src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h。仓库测试验证了典型用法——给objectName属性赋字符串再读回见 src/lib/QtCore/tests/QObject.test.tsconst component new QObject(); component.setProperty(objectName, testObjName); const variant component.property(objectName); console.log(variant.toString()); // testObjName对象命名setObjectName / objectNamesetObjectName(objectName: string): void设置对象名称objectName(): string读取对象名称。对象名在 Qt 中常用于findChild类查找与样式表QSS选择器定位在 NodeGui 的 StyleSheet 中同样可用对象名作为选择器。仓库测试验证了读写闭环setObjectName(hello)后objectName()返回hello见 src/lib/QtCore/tests/QObject.test.ts。C 实现见 src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h。事件与信号addEventListener / removeEventListenerQObject从EventWidget继承了完整的监听体系这也是 NodeGui 事件模型的核心。addEventListener有两种重载形态形态一监听 Qt 信号signaladdEventListenerSignalType extends keyof Signals( signalType: SignalType, callback: Signals[SignalType], options?: EventListenerOptions ): voidsignalType取自对应类的 Signals 接口。例如QObjectSignals定义了objectNameChanged信号见 src/lib/QtCore/QObject.ts。文档给出的示例const button new QPushButton(); button.addEventListener(clicked, (checked) console.log(clicked)); // clicked 是 QPushButtonSignals 接口中的一个信号C 侧该信号通过QOBJECT_SIGNALS_ON_TARGET宏把QObject::objectNameChanged转发到 Node 事件发射器见 src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h。形态二监听 Qt 事件QEventaddEventListener( eventType: WidgetEventTypes, callback: (event?: NativeRawPointerQEvent) void, options?: EventListenerOptions ): voidconst button new QPushButton(); button.addEventListener(WidgetEventTypes.HoverEnter, () console.log(hovered));WidgetEventTypes枚举覆盖了 Qt 的全部事件类型MouseMove、KeyPress、Paint、Resize等上百个见 src/lib/core/EventWidget.ts。EventListenerOptions 选项{ afterDefault?: boolean }。当监听 QEvent 且afterDefault: true时回调会在基类默认事件处理之后执行默认情况下回调在基类::event()之前执行见 src/lib/core/EventWidget.ts。removeEventListener与addEventListener形态一一对应用于注销监听。值得注意的是内部实现会在监听器全部移除后调用native.unSubscribeToQtEvent停止向 Node 侧转发该事件见 src/lib/core/EventWidget.ts。事件处理标记eventProcessed / setEventProcessed这对方法同样继承自EventWidgeteventProcessed(): boolean读取当前事件是否已被标记为“已处理”setEventProcessed(isProcessed: boolean): void在事件处理器内部调用标记当前事件已处理完毕。文档明确指出其语义当标记为已处理时NodeGui 的QObject::event()会返回true且不再调用超类的event()从而阻止该事件被进一步处理。该标记只应在事件处理器中调用才有意义。EventWidget的实现通过_isEventProcessed私有字段维护状态并在分发事件时保存/恢复旧值以支持递归事件分发见 src/lib/core/EventWidget.ts。典型场景在MouseMove等事件回调里调用setEventProcessed(true)阻止事件继续传播到默认处理逻辑。生命周期管理delete / deleteLaterdelete(): void立即销毁底层 C 对象对应宏中deleteObject对QObject*直接delete见 src/cpp/include/nodegui/QtCore/QObject/qobject_macro.hdeleteLater(): void安排对象在事件循环回到事件处理时再销毁Qt 的QObject::deleteLater()语义见 src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h。deleteLater比delete更安全它避免了在事件处理过程中直接删除对象可能引发的崩溃。关于 NodeGui 中对象回收与 WrapperCache 的关系可进一步阅读 website/docs/development/wrapper_caching.md 与 website/docs/guides/understanding-memory.md。计时器startTimer / killTimerstartTimer(intervalMS: number, timerType?: TimerType): number killTimer(timerId: number): voidstartTimer以毫秒为单位启动一个定时器返回定时器 ID后续用该 ID 停止定时器timerType默认TimerType.CoarseTimer见 src/lib/QtCore/QObject.tskillTimer(timerId)根据 ID 停止对应定时器。TimerType枚举定义见 src/lib/QtEnums/TimerType/index.ts枚举值数值语义PreciseTimer0尽可能精确地按时触发CoarseTimer1允许一定的误差以省电默认值VeryCoarseTimer2允许更大误差最省电C 侧startTimer把timerType从 JS number 转换为Qt::TimerType后调用QObject::startTimer()见 src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h。定时器触发后会产生Timer事件WidgetEventTypes.Timer可配合addEventListener(WidgetEventTypes.Timer, ...)接收。小结QObject API 速查表类别API关键说明构造new QObject(parent?)可选父对象内部也可由原生指针恢复对象树parent()/setParent()/children()父子关系驱动生命周期返回均走 WrapperCache标识native/_id()/inherits()_id为内存地址哈希可配合日志调试内存属性setProperty()/property()动态属性值经QVariantType↔QVariant转换命名setObjectName()/objectName()支持 QSS 选择器与查找事件addEventListener()/removeEventListener()信号与 QEvent 双形态支持afterDefault事件标记eventProcessed()/setEventProcessed()在事件处理器内阻止后续默认处理生命周期delete()/deleteLater()立即销毁 vs 事件循环安全销毁计时startTimer()/killTimer()返回定时器 IDTimerType控制精度诊断dumpObjectTree()/dumpObjectInfo()打印对象树/对象信息QObject是理解 NodeGui 一切组件行为对象树管理、动态属性、信号事件、内存生命周期的钥匙。掌握了它就掌握了 NodeGui 中所有QWidget、QLayout、QAction等组件共用的基础能力想要深入了解事件在 C 与 JS 之间的流转机制可继续阅读 website/docs/development/signal_and_event_handling.md想了解封装复用与对象缓存的原理则可参考 website/docs/development/wrapper_caching.md。赞分享桌面应用跨平台【免费下载链接】nodeguiA library for building cross-platform native desktop applications with Node.js and CSS . React NodeGui : https://react.nodegui.org and Vue NodeGui: https://vue.nodegui.org项目地址https://gitcode.com/gh_mirrors/no/nodegui点击查看免费下载相关推荐NodeGui QTreeWidgetSignals 信号接口完全指南从 Qt 树控件事件到 Node.js 回调NodeGui QTreeWidgetSignals 信号接口完全指南从 Qt 树控件事件到 Node.js 回调 QTreeWidgetSignals 是桌面应用跨平台Cytoscape.js 事件系统完全指南事件对象、事件冒泡与全量事件类型详解Cytoscape.js 事件系统完全指南事件对象、事件冒泡与全量事件类型详解 Cytoscape.js 是用于图可视化与图分析的 JavaScript 库数据可视化bootstrap-datepicker 事件系统完全指南show、hide、changeDate 等事件的对象、时机与实战用法bootstrap datepicker 事件系统完全指南show、hide、changeDate 等事件的对象、时机与实战用法 bootstrap date前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表