【C++QT】Item Views 项目视图控件详解
文章目录
- 一、List View(QListView)
- 1. 基本用法
- 2. 特性
- 3. 信号与槽
- 二、Tree View(QTreeView)
- 1. 基本用法
- 2. 特性
- 3. 信号与槽
- 三、Table View(QTableView)
- 1. 基本用法
- 2. 特性
- 3. 信号与槽
- 四、Column View(QColumnView)
- 1. 基本用法
- 2. 特性
- 3. 信号与槽
- 五、总结
- 1. 模型 - 视图架构
- 2. 总结对比
- 3. 最佳实践
- 如果这篇文章对你有所帮助,渴望获得你的一个点赞!
在 Qt 中,Item Views
组控件提供了强大且灵活的方式来展示和管理数据。这些控件基于模型 - 视图(Model - View)架构,将数据的存储和呈现进行分离,使得代码具有更好的可维护性和可扩展性。本文详细介绍了List View
、Tree View
、Table View
和Column View
控件的使用方法和信号与槽示例。
一、List View(QListView)
QListView
用于展示一系列的数据项,以列表的形式呈现。它既可以显示文本,也能展示图标。
1. 基本用法
#include <QApplication>
#include <QListView>
#include <QStandardItemModel>int main(int argc, char *argv[])
{// 创建一个 QApplication 对象,用于管理 GUI 应用程序的资源和事件循环QApplication app(argc, argv);// 创建一个 QStandardItemModel 对象,用于存储和管理列表视图的数据QStandardItemModel model;// 定义一个 QStringList 对象,包含要显示在列表视图中的项目QStringList items = {"Apple", "Banana", "Cherry"};// 遍历 QStringList 中的每个项目for (const QString& item : items) {// 为每个项目创建一个 QStandardItem 对象QStandardItem* standardItem = new QStandardItem(item);// 将 QStandardItem 对象添加到 QStandardItemModel 的行中model.appendRow(standardItem);}// 创建一个 QListView 对象,用于显示列表视图QListView listView;// 将 QStandardItemModel 对象设置为 QListView 的数据模型listView.setModel(&model);// 显示 QListViewlistView.show();// 启动应用程序的事件循环,等待用户交互return app.exec();
}
2. 特性
- 选择模式:可通过
setSelectionMode
方法设置不同的选择模式,如QAbstractItemView::SingleSelection
(单选)、QAbstractItemView::MultiSelection
(多选)等。
listView.setSelectionMode(QAbstractItemView::MultiSelection);
- 显示模式:能通过
setViewMode
方法设置为图标模式(QListView::IconMode
)或列表模式(QListView::ListMode
)。
listView.setViewMode(QListView::IconMode);
3. 信号与槽
**选择项改变信号:**当列表视图中的选择项发生改变时,会发出selectionChanged
信号。下面示例展示了当选择项改变时,会在控制台输出所选项目的文本。
#include <QApplication>
#include <QListView>
#include <QStandardItemModel>
#include <QDebug>
#include <QItemSelectionModel>// 自定义类,用于处理 QListView 的选择改变事件,继承自 QObject
class MyListViewHandler : public QObject
{Q_OBJECT
public:// 构造函数,接收一个 QListView 指针和一个可选的父对象指针// 该构造函数用于初始化成员变量并连接信号和槽explicit MyListViewHandler(QListView* listView, QObject* parent = nullptr): QObject(parent), m_listView(listView){// 连接 QListView 的选择模型的 selectionChanged 信号到当前类的 onSelectionChanged 槽函数// 当列表视图中的选择项发生改变时,会触发 onSelectionChanged 槽函数connect(m_listView->selectionModel(), &QItemSelectionModel::selectionChanged,this, &MyListViewHandler::onSelectionChanged);}private slots:// 处理选择改变事件的槽函数// 当选择项发生改变时,会传入两个参数:新选择的项和取消选择的项void onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected){// 获取新选择项的索引列表QModelIndexList indexes = selected.indexes();// 遍历索引列表for (const QModelIndex& index : indexes) {// 输出选中项的文本信息qDebug() << "Selected item:" << m_listView->model()->data(index).toString();}}private:// 指向 QListView 的指针,用于在类中访问列表视图的相关信息QListView* m_listView;
};int main(int argc, char *argv[])
{// 创建 Qt 应用程序对象QApplication app(argc, argv);// 创建一个标准项模型,用于存储列表视图的数据QStandardItemModel model;// 定义一个字符串列表,包含要显示的项目QStringList items = {"Apple", "Banana", "Cherry"};// 遍历字符串列表for (const QString& item : items) {// 为每个字符串创建一个标准项QStandardItem* standardItem = new QStandardItem(item);// 将标准项添加到模型的行中model.appendRow(standardItem);}// 创建一个列表视图对象QListView listView;// 将模型设置给列表视图,以便列表视图显示模型中的数据listView.setModel(&model);// 创建自定义的处理对象,传入列表视图指针MyListViewHandler handler(&listView);// 显示列表视图listView.show();// 进入应用程序的事件循环,等待用户交互return app.exec();
}
上述示例中,创建了一个自定义的MyListViewHandler
类,在其构造函数中连接了QItemSelectionModel
的selectionChanged
信号到自定义的槽函数onSelectionChanged
。当选择项改变时,该槽函数会输出所选项目的文本。
二、Tree View(QTreeView)
QTreeView
用于展示具有层次结构的数据,非常适合呈现文件系统目录、组织结构图等。
1. 基本用法
#include <QApplication>
#include <QTreeView>
#include <QStandardItemModel>int main(int argc, char *argv[])
{// 创建一个 QApplication 对象,它是 Qt 应用程序的核心,负责管理应用程序的资源、事件循环等QApplication app(argc, argv);// 创建一个 QStandardItemModel 对象,这是一个通用的模型,用于存储和管理树形视图的数据// 构造函数的参数 (2, 2) 表示该模型初始有 2 行 2 列QStandardItemModel model(2, 2);// 设置模型的水平表头标签,这里将第一列设为 "Name",第二列设为 "Value"model.setHorizontalHeaderLabels({"Name", "Value"});// 获取模型的不可见根项,它是树形结构的顶层节点,虽然不可见,但用于管理其他节点QStandardItem* rootItem = model.invisibleRootItem();// 创建一个新的标准项作为父项,文本内容为 "Parent"QStandardItem* parentItem = new QStandardItem("Parent");// 创建一个新的标准项作为子项,文本内容为 "Child"QStandardItem* childItem = new QStandardItem("Child");// 将子项添加到父项的子节点列表中,建立父子关系parentItem->appendRow(childItem);// 将父项添加到模型的不可见根项的子节点列表中,将其纳入整个树形结构rootItem->appendRow(parentItem);// 创建一个 QTreeView 对象,它是用于显示树形结构数据的视图控件QTreeView treeView;// 将前面创建的模型设置给树形视图,这样树形视图就会从该模型获取数据并进行显示treeView.setModel(&model);// 显示树形视图窗口treeView.show();// 启动应用程序的事件循环,使应用程序能够响应用户的操作和系统事件// 该函数会阻塞,直到应用程序退出return app.exec();
}
2. 特性
- 展开与折叠:用户能够通过点击节点来展开或折叠子节点。也可使用代码控制,如
expandAll()
展开所有节点,collapseAll()
折叠所有节点。
treeView.expandAll();
- 多级表头:可设置多级表头来呈现更复杂的数据结构。
3. 信号与槽
节点展开和折叠信号:QTreeView
提供了expanded
和collapsed
信号,分别在节点展开和折叠时发出。下面的示例展示了如何处理这些信号。
#include <QApplication>
#include <QTreeView>
#include <QStandardItemModel>
#include <QDebug>// 自定义类,继承自 QObject,用于处理 QTreeView 的节点展开和折叠事件
class MyTreeViewHandler : public QObject
{// 包含此宏以支持 Qt 的信号与槽机制Q_OBJECT
public:// 构造函数,接收一个 QTreeView 指针和一个可选的父对象指针// 该构造函数用于初始化成员变量并连接信号和槽explicit MyTreeViewHandler(QTreeView* treeView, QObject* parent = nullptr): QObject(parent), m_treeView(treeView){// 连接 QTreeView 的 expanded 信号到当前类的 onNodeExpanded 槽函数// 当树形视图中的某个节点被展开时,会触发 onNodeExpanded 槽函数connect(m_treeView, &QTreeView::expanded, this, &MyTreeViewHandler::onNodeExpanded);// 连接 QTreeView 的 collapsed 信号到当前类的 onNodeCollapsed 槽函数// 当树形视图中的某个节点被折叠时,会触发 onNodeCollapsed 槽函数connect(m_treeView, &QTreeView::collapsed, this, &MyTreeViewHandler::onNodeCollapsed);}private slots:// 处理节点展开事件的槽函数// 当节点展开时,传入该节点的模型索引void onNodeExpanded(const QModelIndex& index){// 使用 qDebug 输出节点展开的信息,包括节点的数据内容qDebug() << "Node expanded:" << m_treeView->model()->data(index).toString();}// 处理节点折叠事件的槽函数// 当节点折叠时,传入该节点的模型索引void onNodeCollapsed(const QModelIndex& index){// 使用 qDebug 输出节点折叠的信息,包括节点的数据内容qDebug() << "Node collapsed:" << m_treeView->model()->data(index).toString();}private:// 指向 QTreeView 的指针,用于在类中访问树形视图的相关信息QTreeView* m_treeView;
};int main(int argc, char *argv[])
{// 创建 Qt 应用程序对象,用于管理应用程序的资源和事件循环QApplication app(argc, argv);// 创建一个标准项模型,初始设置为 2 行 2 列QStandardItemModel model(2, 2);// 设置模型的水平表头标签model.setHorizontalHeaderLabels({"Name", "Value"});// 获取模型的不可见根项QStandardItem* rootItem = model.invisibleRootItem();// 创建一个父节点标准项QStandardItem* parentItem = new QStandardItem("Parent");// 创建一个子节点标准项QStandardItem* childItem = new QStandardItem("Child");// 将子节点添加到父节点下parentItem->appendRow(childItem);// 将父节点添加到根节点下rootItem->appendRow(parentItem);// 创建一个树形视图对象QTreeView treeView;// 将模型设置给树形视图,以便树形视图显示模型中的数据treeView.setModel(&model);// 创建自定义的处理对象,传入树形视图指针MyTreeViewHandler handler(&treeView);// 显示树形视图treeView.show();// 进入应用程序的事件循环,等待用户交互return app.exec();
}
上述示例中,我们创建了一个MyTreeViewHandler
类,在其构造函数中连接了QTreeView
的expanded
和collapsed
信号到相应的槽函数。当节点展开或折叠时,槽函数会输出相应的信息。
三、Table View(QTableView)
QTableView
用于以表格形式展示数据,就像电子表格一样。
1. 基本用法
#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>int main(int argc, char *argv[])
{// 创建一个 QApplication 对象,它是 Qt 应用程序的核心,负责管理应用程序的资源、事件循环等QApplication app(argc, argv);// 创建一个 QStandardItemModel 对象,这是一个用于存储和管理表格数据的模型// 构造函数的参数 (3, 2) 表示该模型初始有 3 行 2 列QStandardItemModel model(3, 2);// 设置模型的水平表头标签,将第一列的表头设为 "Column 1",第二列设为 "Column 2"model.setHorizontalHeaderLabels({"Column 1", "Column 2"});// 使用嵌套的 for 循环遍历表格的每一行和每一列for (int row = 0; row < 3; ++row) {for (int col = 0; col < 2; ++col) {// 创建一个 QStandardItem 对象,该对象表示表格中的一个单元格// 单元格的文本内容是根据当前的行号和列号动态生成的,格式为 "Row X, Col Y"QStandardItem* item = new QStandardItem(QString("Row %1, Col %2").arg(row).arg(col));// 将创建好的单元格对象设置到模型的指定行和列位置model.setItem(row, col, item);}}// 创建一个 QTableView 对象,它是用于显示表格数据的视图控件QTableView tableView;// 将前面创建的模型设置给表格视图,这样表格视图就会从该模型获取数据并进行显示tableView.setModel(&model);// 显示表格视图窗口tableView.show();// 启动应用程序的事件循环,使应用程序能够响应用户的操作和系统事件// 该函数会阻塞,直到应用程序退出return app.exec();
}
2. 特性
- 编辑功能:可通过
setEditTriggers
方法设置编辑触发条件,如双击单元格、按回车键等。
tableView.setEditTriggers(QAbstractItemView::DoubleClicked);
- 列和行的操作:可以对列和行进行隐藏、调整大小、排序等操作。
tableView.setColumnWidth(0, 200); // 设置第一列宽度为200像素
3. 信号与槽
单元格双击信号:QTableView
提供了doubleClicked
信号,当用户双击单元格时会发出该信号。下面的示例展示了如何处理这个信号。
#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>
#include <QDebug>// 自定义类,继承自 QObject,用于处理 QTableView 的单元格双击事件
class MyTableViewHandler : public QObject
{// 包含该宏以支持 Qt 的元对象系统,如信号与槽机制Q_OBJECT
public:// 构造函数,接收一个 QTableView 指针和一个可选的父对象指针// 用于初始化成员变量并建立信号与槽的连接explicit MyTableViewHandler(QTableView* tableView, QObject* parent = nullptr): QObject(parent), m_tableView(tableView){// 连接 QTableView 的 doubleClicked 信号到当前类的 onCellDoubleClicked 槽函数// 当表格视图中的单元格被双击时,会触发 onCellDoubleClicked 槽函数connect(m_tableView, &QTableView::doubleClicked, this, &MyTableViewHandler::onCellDoubleClicked);}private slots:// 处理单元格双击事件的槽函数// 当单元格被双击时,传入该单元格对应的模型索引void onCellDoubleClicked(const QModelIndex& index){// 使用 qDebug 输出单元格被双击的信息,包含单元格的数据内容qDebug() << "Cell double clicked:" << m_tableView->model()->data(index).toString();}private:// 指向 QTableView 的指针,用于在类中访问表格视图的相关信息QTableView* m_tableView;
};int main(int argc, char *argv[])
{// 创建 Qt 应用程序对象,用于管理应用程序的资源和事件循环QApplication app(argc, argv);// 创建一个标准项模型,初始设置为 3 行 2 列QStandardItemModel model(3, 2);// 设置模型的水平表头标签model.setHorizontalHeaderLabels({"Column 1", "Column 2"});// 嵌套循环为模型的每个单元格创建并设置数据for (int row = 0; row < 3; ++row) {for (int col = 0; col < 2; ++col) {// 创建一个标准项,其文本内容为当前单元格的行和列信息QStandardItem* item = new QStandardItem(QString("Row %1, Col %2").arg(row).arg(col));// 将标准项设置到模型的指定行和列位置model.setItem(row, col, item);}}// 创建一个表格视图对象QTableView tableView;// 将模型设置给表格视图,使表格视图显示模型中的数据tableView.setModel(&model);// 创建自定义的处理对象,传入表格视图指针MyTableViewHandler handler(&tableView);// 显示表格视图tableView.show();// 进入应用程序的事件循环,等待用户交互return app.exec();
}
上述示例中,创建了一个MyTableViewHandler
类,在其构造函数中连接了QTableView
的doubleClicked
信号到自定义的槽函数onCellDoubleClicked
。当用户双击单元格时,槽函数会输出该单元格的文本。
四、Column View(QColumnView)
QColumnView
以多列的形式展示具有层次结构的数据,用户可以通过点击不同列中的项目来导航到下一级数据。
1. 基本用法
#include <QApplication>
#include <QColumnView>
#include <QStandardItemModel>int main(int argc, char *argv[])
{// 创建一个 QApplication 实例,它是 Qt 应用程序的核心,负责管理应用程序的资源、事件循环等QApplication app(argc, argv);// 创建一个 QStandardItemModel 对象,这是一个用于存储和管理数据的模型// 构造函数的参数 (2, 1) 表示该模型初始有 2 行 1 列QStandardItemModel model(2, 1);// 获取模型的不可见根项,它是树形结构数据的顶层节点,通常不显示QStandardItem* rootItem = model.invisibleRootItem();// 创建一个新的标准项作为父项,其显示文本为 "Parent"QStandardItem* parentItem = new QStandardItem("Parent");// 创建一个新的标准项作为子项,其显示文本为 "Child"QStandardItem* childItem = new QStandardItem("Child");// 将子项添加到父项的子节点列表中,建立父子关系parentItem->appendRow(childItem);// 将父项添加到模型的不可见根项的子节点列表中,将其纳入整个数据结构rootItem->appendRow(parentItem);// 创建一个 QColumnView 对象,它是一个用于以列的形式展示树形结构数据的视图控件QColumnView columnView;// 将之前创建的模型设置给列视图,让列视图从该模型获取数据并进行展示columnView.setModel(&model);// 显示列视图窗口columnView.show();// 启动应用程序的事件循环,使应用程序能够响应用户的操作和系统事件// 该函数会阻塞,直到应用程序退出return app.exec();
}
2. 特性
- 导航体验:用户通过点击某列中的项目,下一级数据会在右侧新的列中显示,提供了一种直观的导航方式。
- 自适应布局:列的宽度会根据内容自动调整,以适应不同的数据展示需求。
3. 信号与槽
当前列改变信号:QColumnView
提供了currentChanged
信号,当当前列发生改变时会发出该信号。下面的示例展示了如何处理这个信号。
#include <QApplication>
#include <QColumnView>
#include <QStandardItemModel>
#include <QDebug>// 自定义类,继承自 QObject,用于处理 QColumnView 的当前列改变事件
class MyColumnViewHandler : public QObject
{// 包含该宏以支持 Qt 的元对象系统,如信号与槽机制Q_OBJECT
public:// 构造函数,接收一个 QColumnView 指针和一个可选的父对象指针// 用于初始化成员变量并建立信号与槽的连接explicit MyColumnViewHandler(QColumnView* columnView, QObject* parent = nullptr): QObject(parent), m_columnView(columnView){// 连接 QColumnView 的 currentChanged 信号到当前类的 onCurrentColumnChanged 槽函数// 当列视图中的当前列发生改变时,会触发 onCurrentColumnChanged 槽函数connect(m_columnView, &QColumnView::currentChanged, this, &MyColumnViewHandler::onCurrentColumnChanged);}private slots:// 处理当前列改变事件的槽函数// 当当前列改变时,传入新的当前索引和之前的索引void onCurrentColumnChanged(const QModelIndex& current, const QModelIndex& previous){// 使用 qDebug 输出当前列改变的信息,包含新的当前列的数据内容qDebug() << "Current column changed:" << m_columnView->model()->data(current).toString();}private:// 指向 QColumnView 的指针,用于在类中访问列视图的相关信息QColumnView* m_columnView;
};int main(int argc, char *argv[])
{// 创建 Qt 应用程序对象,用于管理应用程序的资源和事件循环QApplication app(argc, argv);// 创建一个标准项模型,初始设置为 2 行 1 列QStandardItemModel model(2, 1);// 获取模型的不可见根项QStandardItem* rootItem = model.invisibleRootItem();// 创建一个父节点标准项QStandardItem* parentItem = new QStandardItem("Parent");// 创建一个子节点标准项QStandardItem* childItem = new QStandardItem("Child");// 将子节点添加到父节点下parentItem->appendRow(childItem);// 将父节点添加到根节点下rootItem->appendRow(parentItem);// 创建一个列视图对象QColumnView columnView;// 将模型设置给列视图,使列视图显示模型中的数据columnView.setModel(&model);// 创建自定义的处理对象,传入列视图指针MyColumnViewHandler handler(&columnView);// 显示列视图columnView.show();// 进入应用程序的事件循环,等待用户交互return app.exec();
}
上述示例中,创建了一个MyColumnViewHandler
类,在其构造函数中连接了QColumnView
的currentChanged
信号到自定义的槽函数onCurrentColumnChanged
。当当前列发生改变时,槽函数会输出当前列的文本。
五、总结
1. 模型 - 视图架构
(1) 统一模型接口:所有Item Views
均通过setModel(QAbstractItemModel*)
关联模型,支持QStandardItemModel
(标准项目模型)或自定义模型。
(2) 交互与选择:
-
均支持选择模型(
QItemSelectionModel
),通过selectionModel()
获取选中项。 -
提供选中、点击、双击等通用信号(如
clicked
、doubleClicked
)。
(3) 自定义展示:
-
可通过
.setItemDelegate
设置委托(QItemDelegate
),自定义单元格的渲染和编辑方式。 -
支持样式表(Qt Style Sheets)和界面定制(如列宽、行高、节点图标等)。
2. 总结对比
控件 | 数据结构 | 展示形式 | 典型场景 | 核心信号(特有) |
---|---|---|---|---|
QTreeView | 树状(层次化) | 树形节点(可展开 / 折叠) | 目录结构、层级数据 | expanded 、collapsed |
QTableView | 二维表格 | 行列表格 | 数据表格、数据库记录 | doubleClicked (单元格) |
QListView | 一维列表 | 列表 / 图标排列 | 项目列表、选项列表 | clicked (行) |
QColumnView | 树状(分层导航) | 多列逐层展开 | 层级路径选择(如文件目录) | currentChanged (列变化) |
3. 最佳实践
- 选择合适的视图:根据数据结构(层次化 / 平面 / 列表)选择对应的视图,避免强行适配。
- 分离数据与展示:通过模型 - 视图架构解耦数据逻辑与界面显示,便于后续扩展(如更换视图或模型)。
- 利用信号槽:通过视图提供的信号(如选择变化、节点状态变化)实现业务逻辑,减少手动操作模型的复杂度。
通过合理使用Item Views
,可高效实现数据的展示与交互,同时保持代码的可维护性和扩展性。