☰
NodeGui QTreeWidgetSignals 信号接口完全指南:从 Qt 树控件事件到 Node.js 回调
2026/9/26 10:21:59 网站建设 项目流程
  • 桌面应用
  • 跨平台

【免费下载链接】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

项目地址:https://gitcode.com/gh_mirrors/no/nodegui
点击查看免费下载

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

在 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信号的生命周期如下:

  1. 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}); });
  1. 参数包装:lambda 内部通过QTreeWidgetItemWrap::fromQTreeWidgetItem把原生QTreeWidgetItem*包装为可供 JS 使用的对象,再连同列号等参数一起传给emitOnNode。

  2. 触发 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

项目地址:https://gitcode.com/gh_mirrors/no/nodegui
点击查看免费下载

相关推荐

上一篇:旧Mac重生指南:用OpenCore Legacy Patcher免费升级最新macOS系统
下一篇:OpenArk被Windows Defender误报?深入解析Windows反病毒软件对ARK工具的误判机制

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询