当前位置: 首页 > news >正文

Qt模型控件:QTreeViewQTreeWidget

QTreeView&QTreeWidget

  • 一、QTreeView
    • 1.1 核心概念:Model/View 架构
    • 1.2 最简单的用法:`QStandardItemModel`
      • 1. QStandardItemModel
        • 核心成员函数
        • `QStandardItem` 的关键函数
        • 总结
    • 1.3 常用功能与属性设置
      • 1. 外观定制
      • 2. 交互性设置
      • 3. 常用操作
    • 1.4 进阶用法:使用自定义模型
    • 1.5 右键菜单 (Context Menu)
    • 1.6 总结
  • 二、QTreeWidget
    • 2.1 核心概念:`QTreeWidget` vs `QTreeView`
    • 2.2 基本用法
    • 2.3 常用功能与属性设置
      • 1. 外观定制
      • 2. 交互性设置
      • 3. 常用操作
    • 2.4 右键菜单 (Context Menu)
    • 2.5 总结:何时使用 `QTreeWidget` vs `QTreeView`

一、QTreeView

QTreeView 是 Qt 中用于显示层级数据(树状结构)的核心控件,功能非常强大和灵活。它通常与**模型(Model)**配合使用,遵循 Model/View 架构。

1.1 核心概念:Model/View 架构

在 Qt 中,QTreeView 是一个视图(View),它本身不存储任何数据。它的职责是显示由**模型(Model)**提供的数据。

  • Model (模型):负责存储数据,并提供标准接口(如 rowCount, data, setData)让 View 可以访问和修改数据。
  • View (视图):负责将 Model 中的数据以特定的视觉形式(如树形、表格、列表)呈现给用户。
  • Delegate (代理):(可选)负责数据的编辑和自定义渲染。

这种分离使得数据管理和界面显示解耦,代码更清晰、更易于维护。

1.2 最简单的用法:QStandardItemModel

对于大多数简单到中等复杂度的应用,QStandardItemModel 是首选。它是一个灵活的、可以存储 QStandardItem 对象的通用模型。

步骤:

  1. 创建 QTreeViewQStandardItemModel
  2. 使用 QStandardItem 创建数据项。
  3. 通过 model->appendRow()parentItem->appendRow() 添加顶层项和子项。
  4. 将 Model 设置到 View 上 (treeView->setModel(model))。

代码示例:

#include <QApplication>
#include <QMainWindow>
#include <QTreeView>
#include <QStandardItemModel>
#include <QStandardItem>int main(int argc, char *argv[])
{QApplication a(argc, argv);QMainWindow mainWindow;mainWindow.setWindowTitle("QTreeView 基础示例");// 1. 创建视图和模型QTreeView *treeView = new QTreeView(&mainWindow);QStandardItemModel *model = new QStandardItemModel(&mainWindow);model->setHeaderData(0, Qt::Horizontal, "项目"); // 设置列标题// 2. 创建根节点 (模型本身就是一个不可见的根)QStandardItem *rootItem = model->invisibleRootItem();// 3. 创建顶层项 "动物" 及其子项QStandardItem *animalItem = new QStandardItem("动物");QStandardItem *dogItem = new QStandardItem("狗");QStandardItem *catItem = new QStandardItem("猫");animalItem->appendRow(dogItem);animalItem->appendRow(catItem);rootItem->appendRow(animalItem);// 4. 创建顶层项 "植物" 及其子项QStandardItem *plantItem = new QStandardItem("植物");QStandardItem *flowerItem = new QStandardItem("花");QStandardItem *treeItem = new QStandardItem("树");plantItem->appendRow(flowerItem);plantItem->appendRow(treeItem);rootItem->appendRow(plantItem);// 5. 将模型设置到视图treeView->setModel(model);// 6. 自动展开所有节点treeView->expandAll();mainWindow.setCentralWidget(treeView);mainWindow.resize(400, 300);mainWindow.show();return a.exec();
}

1. QStandardItemModel

QStandardItemModel 是 Qt 中最常用、最灵活的模型类之一,它属于 Model/View 架构的一部分。它与 QStandardItem 配合使用,可以轻松构建各种复杂的、可编辑的数据结构,如列表、表格和树
QStandardItemModel 是一个基于项(Item)的模型。它的数据由一个二维的 QStandardItem 表格构成。

  • 模型 (Model): QStandardItemModel 本身。
  • 项 (Item): QStandardItem 对象,它是数据的基本单位,每个项可以存储多种角色(Role)的数据(如显示文本、图标、工具提示等)。
  • 索引 (Index): QModelIndex 对象,是访问模型中特定位置数据的“地址”。
核心成员函数
  1. 构造函数

    • QStandardItemModel(QObject *parent = nullptr): 创建一个空模型。
    • QStandardItemModel(int rows, int columns, QObject *parent = nullptr): 创建一个具有指定行数和列数的空模型。
  2. 设置和获取数据
    这些函数是 QStandardItemModel 的核心,用于操作模型中的 QStandardItem

    • QStandardItem *item(int row, int column = 0) const:

      • 功能: 获取指定行、列位置的 QStandardItem 指针。如果该位置没有项,则返回 nullptr
      • 示例: QStandardItem *myItem = model->item(0, 0);
    • void setItem(int row, int column, QStandardItem *item):

      • 功能: 在指定的行、列位置设置一个 QStandardItem。模型会接管该 item 的所有权,你不需要手动 delete 它。
      • 示例:
      QStandardItem *newItem = new QStandardItem("Hello");
      model->setItem(0, 0, newItem);
      
    • QList<QStandardItem *> findItems(const QString &text, Qt::MatchFlags flags = Qt::MatchExactly, int column = 0) const:

      • 功能: 根据文本查找项。flags 参数可以指定匹配方式(如 Qt::MatchExactly 精确匹配, Qt::MatchContains 包含匹配)。
      • 示例:
      QList<QStandardItem*> foundItems = model->findItems("apple", Qt::MatchContains);
      
  3. 操作行和列
    这些函数用于在模型中动态地添加或删除行和列。

    • bool insertRow(int row, const QList<QStandardItem *> &items):

      • 功能: 在指定行 row 插入一行。items 列表中的项将填充新行的各个列。
      • 示例:
      QList<QStandardItem*> newRowItems;
      newRowItems << new QStandardItem("New Item 1") << new QStandardItem("New Item 2");
      model->insertRow(model->rowCount(), newRowItems); // 在末尾插入一行
      
    • bool insertColumn(int column, const QList<QStandardItem *> &items):

      • 功能: 在指定列 column 插入一列。items 列表中的项将填充新列的各个行。
    • void appendRow(const QList<QStandardItem *> &items):

      • 功能: 在模型末尾添加一行。这是 insertRow(model->rowCount(), items) 的便捷版本。
      • 示例 (添加顶层项):
      QStandardItem *topLevelItem = new QStandardItem("顶层项");
      model->appendRow(topLevelItem);
      
    • bool removeRow(int row):

      • 功能: 删除指定的行。该行上的所有 QStandardItem 都会被自动删除。
    • bool removeColumn(int column):

      • 功能: 删除指定的列。该列上的所有 QStandardItem 都会被自动删除。
    • int rowCount(const QModelIndex &parent = QModelIndex()) const:

      • 功能: 返回指定父项 parent 下的行数。对于顶层项,parentQModelIndex()

      • int columnCount(const QModelIndex &parent = QModelIndex()) const:

      • 功能: 返回指定父项 parent 下的列数。

  4. 处理树状结构 (父项和子项)
    QStandardItemModel 天生支持树状结构,通过 QStandardItemappendRow() 方法可以轻松实现。

    • QStandardItem *invisibleRootItem() const:

      • 功能: 返回模型的一个不可见的根项。模型中的所有顶层项都是这个根项的子项。这在处理树状结构时非常有用,可以统一地对所有顶层项进行操作。
      • 示例:
      QStandardItem *root = model->invisibleRootItem();
      QStandardItem *item1 = new QStandardItem("Item 1");
      QStandardItem *item2 = new QStandardItem("Item 2");
      root->appendRow(item1);
      root->appendRow(item2);
      
    • QModelIndex indexFromItem(const QStandardItem *item) const:

      • 功能: 根据一个 QStandardItem 指针获取其对应的 QModelIndex。这在需要将项的位置传递给视图时非常有用。
    • QStandardItem *itemFromIndex(const QModelIndex &index) const:

      • 功能: 根据一个 QModelIndex 获取其对应的 QStandardItem 指针。这是 item() 函数的另一种形式。
  5. 其他常用函数

    • void setHorizontalHeaderLabels(const QStringList &labels):

      • 功能: 设置水平标题栏的标签。
      • 示例: model->setHorizontalHeaderLabels(QStringList() << "Name" << "Age");
    • void clear():

      • 功能: 清除模型中的所有数据和项,将模型重置为空状态。
    • void sort(int column, Qt::SortOrder order = Qt::AscendingOrder):

      • 功能: 根据指定的列对模型数据进行排序。
QStandardItem 的关键函数

QStandardItemModel 的强大之处在于 QStandardItem,以下是 QStandardItem 的一些关键函数:

  • QStandardItem(const QString &text, int type = Type): 构造函数,创建一个带有文本的项。
  • void setText(const QString &text): 设置项的显示文本。
  • QString text() const: 获取项的显示文本。
  • void setData(const QVariant &value, int role = Qt::UserRole + 1): 设置项的特定角色(Role)的数据。角色是 QStandardItem 最强大的特性之一。
    • Qt::DisplayRole: 显示文本 (QString)。
    • Qt::DecorationRole: 图标 (QIcon)。
    • Qt::ToolTipRole: 工具提示 (QString)。
    • Qt::UserRole: 自定义数据的起点。
    • 示例: item->setData(42, Qt::UserRole); // 存储一个自定义的整数值
  • QVariant data(int role = Qt::UserRole + 1) const: 获取项的特定角色的数据。
    • 示例: int value = item->data(Qt::UserRole).toInt();
  • void appendRow(QStandardItem *item): 向当前项添加一个子项。这是构建树状结构的核心。
    • 示例:
      QStandardItem *parentItem = model->item(0);
      QStandardItem *childItem = new QStandardItem("Child");
      parentItem->appendRow(childItem);
      
总结

QStandardItemModel 是一个功能强大且易于使用的模型类。

  • 核心: 由 QStandardItem 对象组成的二维表格。
  • 强项:
    1. 简单直观: API 设计友好,比直接继承 QAbstractItemModel 简单得多。
    2. 功能全面: 同时支持列表、表格和树状结构。
    3. 数据丰富: 通过 QStandardItemsetData()data() 方法,可以为每个单元格存储多种角色的数据。
  • 适用场景: 当你需要一个灵活的数据容器,并且数据量不是特别巨大(例如,几千到几万行以内)时,QStandardItemModel 是你的首选。对于超大规模数据或需要高度优化性能的场景,才考虑创建自定义模型。

1.3 常用功能与属性设置

QTreeView 提供了大量函数来定制其外观和行为。

1. 外观定制

  • setHeaderHidden(bool hidden): 隐藏或显示标题栏。
    treeView->setHeaderHidden(true);
    
  • setIndentation(int i): 设置子项相对于父项的缩进像素。
    treeView->setIndentation(20);
    
  • setRootIsDecorated(bool show): 设置是否显示根节点的展开/折叠图标。对于只有一个顶层项的树,通常设为 false
    treeView->setRootIsDecorated(false);
    

2. 交互性设置

  • setEditTriggers(EditTriggers triggers): 设置触发编辑的方式。
    // 设置为双击或按 F2 时可编辑
    treeView->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
    
  • setSelectionMode(SelectionMode mode): 设置选择模式(单选、多选等)。
    // 允许选择多个项
    treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    
  • setSelectionBehavior(SelectionBehavior behavior): 设置选择行为(选择整行、整列或单个单元格)。
    // 点击时选择整行
    treeView->setSelectionBehavior(QAbstractItemView::SelectRows);
    

3. 常用操作

  • 获取当前选中项:
    // 获取当前选中的顶层项
    QModelIndex currentIndex = treeView->currentIndex();
    if (currentIndex.isValid()) {QString text = currentIndex.data(Qt::DisplayRole).toString();qDebug() << "当前选中项:" << text;
    }
    
  • 展开/折叠所有节点:
    treeView->expandAll();
    treeView->collapseAll();
    
  • 信号与槽: QTreeView 继承自 QAbstractItemView,提供了丰富的信号,如 clicked, doubleClicked, pressed, activated 等。
    connect(treeView, &QTreeView::clicked, [](const QModelIndex &index) {QString text = index.data(Qt::DisplayRole).toString();qDebug() << "点击了项:" << text;
    });
    

1.4 进阶用法:使用自定义模型

当你的数据结构非常复杂,或者需要更好的性能和控制时(例如,数据量巨大,或数据来自数据库),你应该创建自己的模型。

你需要继承 QAbstractItemModel必须重写以下纯虚函数:

  • rowCount(const QModelIndex &parent): 返回指定父项下的行数。
  • columnCount(const QModelIndex &parent): 返回指定父项下的列数。
  • data(const QModelIndex &index, int role): 返回指定索引和角色的数据。
  • index(int row, int column, const QModelIndex &parent): 创建并返回一个索引。
  • parent(const QModelIndex &index): 返回指定索引的父索引。

这部分比较复杂,但提供了无与伦比的灵活性。

1.5 右键菜单 (Context Menu)

QTreeView 添加右键菜单是非常常见的需求。

步骤:

  1. 在构造函数中设置 treeView->setContextMenuPolicy(Qt::CustomContextMenu)
  2. 连接 customContextMenuRequested(const QPoint &) 信号到一个槽函数。
  3. 在槽函数中,创建 QMenuQAction,并使用 exec() 显示菜单。

代码示例:

// 在构造函数中
treeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(treeView, &QTreeView::customContextMenuRequested, this, &MainWindow::showContextMenu);// 槽函数实现
void MainWindow::showContextMenu(const QPoint &pos)
{// 将视图坐标转换为模型索引QModelIndex index = treeView->indexAt(pos);QMenu menu;QAction *addAction = menu.addAction("添加子项");QAction *deleteAction = menu.addAction("删除项");// 如果点击在无效索引上,则禁用某些操作deleteAction->setEnabled(index.isValid());QAction *selectedAction = menu.exec(treeView->viewport()->mapToGlobal(pos));if (selectedAction == addAction) {// 添加子项的逻辑...} else if (selectedAction == deleteAction) {// 删除项的逻辑...// 注意:删除操作应该通过模型来完成// model->removeRow(index.row(), index.parent());}
}

1.6 总结

QTreeView 是一个功能极其强大的控件,其核心在于与 Model 的分离。

  • 入门:使用 QStandardItemModel 可以快速构建树状结构。
  • 定制:通过 set... 系列函数可以轻松改变 QTreeView 的外观和交互方式。
  • 交互:利用信号和槽(如 clicked, customContextMenuRequested)响应用户操作。
  • 进阶:对于复杂或高性能需求,创建自定义模型继承 QAbstractItemModel

二、QTreeWidget

QTreeWidgetQTreeView 的一个便捷子类,它将视图(View)和模型(Model)合二为一,封装了 QTreeViewQStandardItemModel 的组合,使得创建简单的树状结构变得更加容易。

如果你不需要自定义数据结构或复杂的模型逻辑,QTreeWidget 是一个非常好的选择。

2.1 核心概念:QTreeWidget vs QTreeView

  • QTreeWidget: “即插即用” 的树控件。它内部自带一个 QStandardItemModel,你只需要和 QTreeWidgetItem 打交道,而不需要关心底层的模型接口。
  • QTreeView: 高度灵活的树视图。它必须与一个独立的模型(如 QStandardItemModel 或自定义模型)配合使用。这种分离使得它可以处理更复杂的数据和场景。

简单来说,QTreeWidget 是为了方便而设计的,而 QTreeView 是为了灵活而设计的。

2.2 基本用法

使用 QTreeWidget 的核心是 QTreeWidgetItem,每个 QTreeWidgetItem 代表树中的一个节点(项)。

步骤:

  1. 创建 QTreeWidget 控件。
  2. (可选)设置列数和列标题。
  3. 创建 QTreeWidgetItem 对象作为顶层项(根项)。
  4. 使用 addTopLevelItem() 将顶层项添加到 QTreeWidget
  5. 创建其他 QTreeWidgetItem 对象作为子项。
  6. 使用 QTreeWidgetItem::addChild() 将子项添加到其父项。

代码示例:

#include <QApplication>
#include <QMainWindow>
#include <QTreeWidget>
#include <QTreeWidgetItem>int main(int argc, char *argv[])
{QApplication a(argc, argv);QMainWindow mainWindow;mainWindow.setWindowTitle("QTreeWidget 基础示例");// 1. 创建 QTreeWidget 控件QTreeWidget *treeWidget = new QTreeWidget(&mainWindow);// 2. 设置列数和列标题 (如果是多列树)// 对于单列树,这一步可以省略QStringList headers;headers << "项目" << "描述";treeWidget->setHeaderLabels(headers);// 3. 创建顶层项 "动物"QTreeWidgetItem *animalItem = new QTreeWidgetItem(QStringList() << "动物");// 4. 将顶层项添加到树控件treeWidget->addTopLevelItem(animalItem);// 5. 创建子项并添加到 "动物"QTreeWidgetItem *dogItem = new QTreeWidgetItem(QStringList() << "狗" << "忠诚的伙伴");QTreeWidgetItem *catItem = new QTreeWidgetItem(QStringList() << "猫" << "高冷的主子");animalItem->addChild(dogItem);animalItem->addChild(catItem);// 6. 创建另一个顶层项 "植物"QTreeWidgetItem *plantItem = new QTreeWidgetItem(QStringList() << "植物");treeWidget->addTopLevelItem(plantItem);// 7. 创建子项并添加到 "植物"QTreeWidgetItem *flowerItem = new QTreeWidgetItem(QStringList() << "花" << "美丽的植物");QTreeWidgetItem *treeItem = new QTreeWidgetItem(QStringList() << "树" << "高大的植物");plantItem->addChild(flowerItem);plantItem->addChild(treeItem);// 自动展开所有节点treeWidget->expandAll();mainWindow.setCentralWidget(treeWidget);mainWindow.resize(400, 300);mainWindow.show();return a.exec();
}

2.3 常用功能与属性设置

QTreeWidget 的许多方法与 QTreeView 类似,因为它继承自 QTreeView

1. 外观定制

  • setHeaderHidden(bool hidden): 隐藏或显示标题栏。
  • setIndentation(int i): 设置子项缩进。
  • setRootIsDecorated(bool show): 设置是否显示根节点的展开/折叠图标。

2. 交互性设置

  • setEditTriggers(EditTriggers triggers): 设置编辑触发方式。
  • setSelectionMode(SelectionMode mode): 设置选择模式。
  • setSelectionBehavior(SelectionBehavior behavior): 设置选择行为。

3. 常用操作

  • 获取当前选中项:
    // 获取所有选中的项
    QList<QTreeWidgetItem*> selectedItems = treeWidget->selectedItems();
    if (!selectedItems.isEmpty()) {QTreeWidgetItem *firstSelected = selectedItems.first();QString text = firstSelected->text(0); // 获取第0列的文本qDebug() << "当前选中项:" << text;
    }
    
  • 获取当前项的父/子项:
    QTreeWidgetItem *currentItem = treeWidget->currentItem();
    if (currentItem) {QTreeWidgetItem *parentItem = currentItem->parent();int childCount = currentItem->childCount();// ...
    }
    
  • 添加/删除项:
    // 添加顶层项
    treeWidget->addTopLevelItem(new QTreeWidgetItem(QStringList() << "新顶层项"));// 删除当前选中项
    QTreeWidgetItem *currentItem = treeWidget->currentItem();
    if (currentItem) {// 如果是顶层项if (!currentItem->parent()) {int index = treeWidget->indexOfTopLevelItem(currentItem);treeWidget->takeTopLevelItem(index);} else {// 如果是子项QTreeWidgetItem *parent = currentItem->parent();int index = parent->indexOfChild(currentItem);parent->takeChild(index);}delete currentItem; // 释放内存
    }
    
  • 信号与槽: QTreeWidget 同样提供了丰富的信号,如 itemClicked, itemDoubleClicked, itemPressed 等。
    connect(treeWidget, &QTreeWidget::itemClicked, [](QTreeWidgetItem *item, int column) {qDebug() << "点击了项:" << item->text(column) << "在列:" << column;
    });
    

2.4 右键菜单 (Context Menu)

QTreeWidget 添加右键菜单的方法与 QTreeView 类似。

步骤:

  1. 设置 treeWidget->setContextMenuPolicy(Qt::CustomContextMenu)
  2. 连接 customContextMenuRequested(const QPoint &) 信号。
  3. 在槽函数中,使用 itemAt(const QPoint &) 获取鼠标位置下的项。

代码示例:

// 在构造函数中
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, &MainWindow::showContextMenu);// 槽函数实现
void MainWindow::showContextMenu(const QPoint &pos)
{// 获取鼠标位置下的项QTreeWidgetItem *item = treeWidget->itemAt(pos);QMenu menu;QAction *addAction = menu.addAction("添加子项");QAction *deleteAction = menu.addAction("删除项");// 如果没有点击任何项,则禁用操作addAction->setEnabled(item != nullptr);deleteAction->setEnabled(item != nullptr);QAction *selectedAction = menu.exec(treeWidget->viewport()->mapToGlobal(pos));if (selectedAction == addAction && item) {item->addChild(new QTreeWidgetItem(QStringList() << "新子项"));item->setExpanded(true); // 展开父项以显示新子项} else if (selectedAction == deleteAction && item) {// 删除项的逻辑...// ... (同上一节的删除代码)}
}

2.5 总结:何时使用 QTreeWidget vs QTreeView

特性QTreeWidgetQTreeView
易用性非常高。API 直观,开箱即用。较低。需要理解 Model/View 架构,代码更复杂。
灵活性较低。功能被封装,难以深度定制。极高。可以与任何模型(包括自定义模型)配合,实现任何功能。
性能对于大数据量可能稍逊。可以通过自定义模型实现懒加载等优化,性能更好。
数据来源主要用于内存中的静态或半静态数据。可以连接到数据库、文件系统、网络等任何数据源。
推荐场景- 简单的配置树
- 文件浏览器的简化版
- 任何不需要复杂数据处理的层级列表
- 处理海量数据
- 需要自定义数据结构
- 数据来自数据库或其他复杂源
- 需要高度定制的渲染和编辑

结论:

  • 当你需要快速创建一个简单的、数据量不大的树状列表时,毫不犹豫地选择 QTreeWidget
  • 当你预见到数据结构会变得复杂,或者性能是一个关键考量时,从一开始就应该使用 QTreeViewQStandardItemModel,这样可以避免未来重写大量代码。
http://www.dtcms.com/a/482741.html

相关文章:

  • 河南省城乡建设厅官网廊坊快速优化排名
  • 网站建设应该考虑哪些问题企信宝
  • 青海做网站最好的公司互联网推广引流
  • 一天一个设计模式——装饰器模式
  • 婚恋交友 APP 核心功能分析:从匹配逻辑到用户体验的全链路设计
  • 用一个 prompt 搭建带 React 界面的 Java 桌面应用
  • 宁波建网站价格wordpress注明网站
  • wordpress添加网站地图黑龙江新闻头条最新消息
  • 机械臂装配自动化推动紧固件设计革新
  • JSAR 入门教程:从零开始开发空间天气小摆件
  • 【Pytorch】什么是梯度
  • 核间通信机制
  • 吕口*云蛇激光*VS*薄利魔刀*武打算法的方案
  • CSP-S模拟赛五总结(实际难度远低于提高组)
  • 网站建设服务器的配置wordpress 输出sql
  • 邵阳建设网站公司app在线生成平台 免费
  • 如何在第三方网站做推广什么关键词可以搜到那种
  • 深度解析 PostgreSQL 中的 ctid、xmin、xmax:从原理到实战
  • 2-sat
  • KPI、OKR 和 GS 的区别
  • 坂田网站建设费用明细wordpress 最近登录地址
  • 网站开发技术微信公众平台如何绑定网站
  • electron+react+esbuild入门项目
  • iOS 应用加固与苹果软件混淆指南,如何防止 IPA 被反编译与二次打包?
  • jsp电商网站怎么做网络营销是什么部门
  • 网站优化体验报告百度网盟推广步骤
  • 物联网系统三层架构解析
  • 京东联手广汽、宁德时代造车!
  • PEFT适配器加载
  • React Hooks 核心规则自定义 Hooks