- 桌面应用
- 跨平台
【免费下载链接】nodegui
A 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
QTreeWidgetSignals是 NodeGui 中树形视图控件QTreeWidget的信号接口定义,它完整刻画了 Qt 的QTreeWidget在 Node.js 世界中的事件面:项目点击、双击、展开/折叠、选中变化、内容编辑、当前项切换等 10 个原生信号,以及从父级接口继承的 4 个通用信号。读完本文,你将掌握如何为QTreeWidget挂载事件监听、理解每个信号回调的参数含义,并能从源码层面看懂这些 Qt 信号是如何被转译为 Node.js 事件的。
接口定位:QTreeWidgetSignals 在整个信号体系中的位置
在 NodeGui 中,每个原生控件都对应一个"信号接口"(Signals interface),用于声明该控件能够对外发出哪些事件。这些接口之间存在严格的继承层级,与 Qt 的类继承关系一一对应。从生成文档的 Hierarchy 一节可以看到:
- QObjectSignals(基础:
objectNameChanged)- ↳ QWidgetSignals(
customContextMenuRequested、windowIconChanged、windowTitleChanged)- ↳QTreeWidgetSignals
- ↳ QWidgetSignals(
在 TypeScript 源码侧,QTreeWidgetSignals实际扩展自QAbstractScrollAreaSignals(见 src/lib/QtWidgets/QTreeWidget.ts),而生成的 API 文档将其继承关系精简表示为直接继承QWidgetSignals。这与类实现一致:QTreeWidget的 TS 封装继承自QAbstractScrollArea,C++ 侧NTreeWidget则继承自QTreeWidget与NodeWidget(见 src/cpp/include/nodegui/QtWidgets/QTreeWidget/ntreewidget.hpp)。
因此,一个QTreeWidget实例实际可监听到的信号分为两类:自有的树控件信号(10 个)与继承的通用信号(4 个),合计 14 个。
信号总览
| 信号名 | 回调签名 | 触发时机 | 来源 |
|---|---|---|---|
currentItemChanged | (current, previous) => void | 当前项目切换 | 自有 |
itemActivated | (item \| null, column) => void | 项目被激活(如回车或双击,取决于平台) | 自有 |
itemChanged | (item, column) => void | 项目数据被修改 | 自有 |
itemClicked | (item, column) => void | 鼠标点击项目 | 自有 |
itemCollapsed | (item) => void | 项目被折叠 | 自有 |
itemDoubleClicked | (item \| null, column) => void | 鼠标双击项目 | 自有 |
itemEntered | (item, column) => void | 鼠标悬停进入项目(需开启鼠标跟踪) | 自有 |
itemExpanded | (item) => void | 项目被展开 | 自有 |
itemPressed | (item \| null, column) => void | 鼠标按下项目 | 自有 |
itemSelectionChanged | () => void | 选中集发生变化 | 自有 |
customContextMenuRequested | (pos: {x, y}) => void | 请求弹出上下文菜单 | 继承自 QWidgetSignals |
objectNameChanged | (objectName) => void | 对象名变化 | 继承自 QObjectSignals |
windowIconChanged | (iconNative) => void | 窗口图标变化 | 继承自 QWidgetSignals |
windowTitleChanged | (title) => void | 窗口标题变化 | 继承自 QWidgetSignals |
自有信号逐一详解
1. currentItemChanged:当前项目切换
currentItemChanged: (current: QTreeWidgetItem, previous: QTreeWidgetItem) => void;当树中"当前项目"(有焦点、以虚线框高亮的项目)发生变化时触发,回调同时给出切换后的新项目current与切换前的旧项目previous,两个参数都是 QTreeWidgetItem 实例。该信号非常适合实现"主从联动"界面——例如左侧树选中某分类时,右侧面板展示对应详情。
2. itemActivated:项目激活
itemActivated: (item: QTreeWidgetItem | null, column: number) => void;当项目被激活时触发。所谓"激活"通常指双击或按回车键(具体行为与平台和视图设置相关)。注意回调的item参数类型为QTreeWidgetItem | null——Qt 原生信号中该指针可能为空,因此在回调内应先判空再访问。
3. itemChanged:项目内容被编辑
itemChanged: (item: QTreeWidgetItem, column: number) => void;当项目的某一列数据发生变化时触发(例如通过setText、setCheckState修改,或用户在可编辑项目中直接编辑)。回调携带被修改的item与对应column列号。结合 QTreeWidgetItem.ts 中对setText、setCheckState等方法的封装,可以实现数据校验、自动保存、脏标记等业务逻辑。
4. itemClicked / itemPressed:点击与按下
itemClicked: (item: QTreeWidgetItem, column: number) => void; itemPressed: (item: QTreeWidgetItem | null, column: number) => void;itemClicked在鼠标左键单击项目时触发,携带被点击的项目与其所在列;itemPressed在鼠标按下(尚未释放)时触发。二者语义上类似 Qt 按钮的pressed与clicked:需要区分"按下即响应"与"释放后响应"两种交互时分别监听。注意itemPressed的item参数同样可能为null。
5. itemCollapsed / itemExpanded:展开与折叠
itemCollapsed: (item: QTreeWidgetItem) => void; itemExpanded: (item: QTreeWidgetItem) => void;当项目被折叠或展开时触发(用户点击展开箭头、或代码调用setExpanded等)。这两个信号只携带item参数。典型应用是"懒加载"——在itemExpanded回调中才为节点动态添加子项目,避免一次性构建整棵大树。
6. itemDoubleClicked:双击
itemDoubleClicked: (item: QTreeWidgetItem | null, column: number) => void;双击项目时触发,携带项目与列号。item参数同样可为null,需判空。
7. itemEntered:鼠标悬停进入
itemEntered: (item: QTreeWidgetItem, column: number) => void;当鼠标移动进入某个项目所在区域时触发。注意:该信号依赖鼠标跟踪,若需使用需先开启setMouseTracking(true)(可参考 handle-events.md 中对QLabel使用MouseMove的示例思路)。
8. itemSelectionChanged:选中集变化
itemSelectionChanged: () => void;这是唯一一个无参数的自有信号:只要选中集合发生变化(新增、取消选中、切换多选等)即触发,不携带具体项目。需要获取当前选中项时,可在回调中调用QTreeWidget的selectedItems()方法(见 src/lib/QtWidgets/QTreeWidget.ts),它会返回包装后的QTreeWidgetItem[]。
继承的通用信号
- customContextMenuRequested:
(pos: { x: number, y: number }) => void,请求弹出上下文菜单时触发,pos为控件内坐标对象。可配合QMenu实现右键菜单; - objectNameChanged:
(objectName: string) => void,objectName变化时触发,继承自 QObjectSignals; - windowIconChanged:
(iconNative: NativeElement) => void,窗口图标变化时触发,参数为原生图标句柄(类型见 globals.md 中的NativeElement); - windowTitleChanged:
(title: string) => void,窗口标题变化时触发。
这些通用信号在 QWidgetSignals 与 QObjectSignals 接口文档中均有完整定义,NodeGui 中所有控件(如QPushButton、QListWidget、QMainWindow等)都共享它们。
在 NodeGui 中监听这些信号
NodeGui 的信号订阅统一通过addEventListener完成。根据 handle-events.md 的说明,每个控件背后都是一个 Node.jsEventEmitter实例:原生 Qt 控件把信号推送到这个事件发射器,JS 侧通过addEventListener订阅。同一信号可注册多个监听器,全部会被依次调用;使用 TypeScript 时回调参数自动获得类型提示。
一个完整的实战示例(结合 QTreeWidget.ts 中的树构建 API):
const { QMainWindow, QTreeWidget, QTreeWidgetItem } = require('@nodegui/nodegui'); const win = new QMainWindow(); const tree = new QTreeWidget(); // 构建树:顶层项目 + 子项目 const item1 = new QTreeWidgetItem(); item1.setText(0, 'item-1'); const item2 = new QTreeWidgetItem(); item2.setText(0, 'item-2'); tree.addTopLevelItem(item1); tree.addTopLevelItem(item2); const child1 = new QTreeWidgetItem(item1); child1.setText(0, 'child-1'); const child2 = new QTreeWidgetItem(item1); child2.setText(0, 'child-2'); // 订阅信号 tree.addEventListener('currentItemChanged', (current, previous) => { console.log('当前项目切换到:', current.text(0), '上一个:', previous && previous.text(0)); }); tree.addEventListener('itemClicked', (item, column) => { console.log(`点击了第 ${column} 列的项目:`, item.text(column)); }); tree.addEventListener('itemExpanded', (item) => { console.log('展开节点:', item.text(0)); }); tree.addEventListener('itemSelectionChanged', () => { const selected = tree.selectedItems(); console.log('当前选中:', selected.map((it) => it.text(0))); }); win.setCentralWidget(tree); win.show(); global.win = win; // 防止被垃圾回收如果你想知道某个控件到底支持哪些信号,直接阅读对应控件类的签名接口即可——QTreeWidget的信号面就是本文的QTreeWidgetSignals。
源码视角:Qt 信号如何抵达 JS 回调
理解信号的底层流转,可以让排查问题事半功倍。在 NodeGui 中,一条QTreeWidget信号的生命周期如下:
- C++ 侧连接信号:
NTreeWidget继承QTreeWidget与NodeWidget,并在connectSignalsToEventEmitter()中用QObject::connect将每个 Qt 信号与一个 lambda 绑定(见 ntreewidget.hpp)。例如:
QObject::connect(this, &QTreeWidget::itemClicked, = { Napi::Env env = this->emitOnNode.Env(); Napi::HandleScope scope(env); auto itemWrap = QTreeWidgetItemWrap::fromQTreeWidgetItem(env, item); auto columnWrap = Napi::Value::From(env, column); this->emitOnNode.Call( {Napi::String::New(env, "itemClicked"), itemWrap, columnWrap}); });参数包装:lambda 内部通过
QTreeWidgetItemWrap::fromQTreeWidgetItem把原生QTreeWidgetItem*包装为可供 JS 使用的对象,再连同列号等参数一起传给emitOnNode。触发 EventEmitter:
emitOnNode指向 JS 侧EventEmitter的emit函数,由EventWidget在初始化时通过initNodeEventEmitter注入。信号到达后即触发 JS 回调,完成"Qt 信号 → Node.js 事件"的转译。这一整体机制在 eventwidget.h 与 signal_and_event_handling.md 中有详细说明。
值得注意的细节:在 C++ 实现中,itemClicked、itemChanged、currentItemChanged、itemActivated、itemDoubleClicked、itemEntered、itemPressed这些携带项目的信号都会先经fromQTreeWidgetItem包装,所以 JS 回调里拿到的是可直接调用text()等方法的QTreeWidgetItem实例;而itemSelectionChanged由于 Qt 原生信号不带参数,JS 回调中也就没有参数,需要主动调用selectedItems()获取选中项。
常见问题与注意事项
itemActivated/itemDoubleClicked/itemPressed的 item 可能为 null:回调中务必先判空再访问,避免TypeError;itemEntered默认不触发:需要先在控件上开启鼠标跟踪(setMouseTracking(true)),否则悬停信号不会到来;- 信号监听与垃圾回收:与 NodeGui 中其他控件一样,需要把窗口/控件保存在全局引用(如示例中的
global.win)中,防止被 GC 回收导致信号失效,相关机制可参阅 understanding-memory.md; itemChanged与编辑能力:QTreeWidgetItem是否可编辑取决于其ItemFlag设置,若项目不可编辑,用户无法在界面上修改文本,itemChanged主要通过代码层面的setText、setCheckState等触发;- 多列场景:绝大多数信号回调都携带
column列号,处理多列表格(如"名称 + 状态"两列)时记得按列区分业务。
延伸阅读
- QTreeWidget 类参考 与 QTreeWidgetItem 类参考:树控件的全部方法与属性
- QWidgetSignals 与 QObjectSignals:继承信号的完整定义
- handle-events.md:NodeGui 信号与 QEvent 的统一监听方式
- signal_and_event_handling.md:如何在源码层面为控件新增信号支持
- 树控件信号接口源码:QTreeWidget.ts、ntreewidget.hpp、qtreewidget_wrap.cpp
- 桌面应用
- 跨平台
【免费下载链接】nodegui
A 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
相关推荐
NodeGui 中 QTreeWidget 树形控件的完整实战指南:从顶层项管理到信号事件
NodeGui 中 QTreeWidget 树形控件的完整实战指南:从顶层项管理到信号事件 QTreeWidget 是 NodeGui 提供的树形视图控件,它直
桌面应用跨平台30分钟产出研究简报:Academic Research Skills 快速研究模式完整指南
30分钟产出研究简报:Academic Research Skills 快速研究模式完整指南 周五晚上十点,明早的组会需要你讲清楚「AI 评测方法」这个完全陌生
桌面应用跨平台NodeGui QListWidgetSignals 信号接口全解析:从事件监听到 C++ 底层实现
NodeGui QListWidgetSignals 信号接口全解析:从事件监听到 C++ 底层实现 本指南以 NodeGui 官方 API 文档 qlistw
桌面应用跨平台
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考