### 目录
- [@[TOC](目录)](#目录 @TOC 前言 一、QStandardItemModel初步介绍 二、基本功能 1.创建 2.基本属性与方法 三、何时使用 QStandardItemModel? 四、何时避免使用 QStandardItemModel?)
- [前言](#目录 @TOC 前言 一、QStandardItemModel初步介绍 二、基本功能 1.创建 2.基本属性与方法 三、何时使用 QStandardItemModel? 四、何时避免使用 QStandardItemModel?)
- [一、QStandardItemModel初步介绍](#目录 @TOC 前言 一、QStandardItemModel初步介绍 二、基本功能 1.创建 2.基本属性与方法 三、何时使用 QStandardItemModel? 四、何时避免使用 QStandardItemModel?)
- [二、基本功能](#目录 @TOC 前言 一、QStandardItemModel初步介绍 二、基本功能 1.创建 2.基本属性与方法 三、何时使用 QStandardItemModel? 四、何时避免使用 QStandardItemModel?)
- [1.创建](#目录 @TOC 前言 一、QStandardItemModel初步介绍 二、基本功能 1.创建 2.基本属性与方法 三、何时使用 QStandardItemModel? 四、何时避免使用 QStandardItemModel?)
- [2.基本属性与方法](#目录 @TOC 前言 一、QStandardItemModel初步介绍 二、基本功能 1.创建 2.基本属性与方法 三、何时使用 QStandardItemModel? 四、何时避免使用 QStandardItemModel?)
- [三、何时使用 QStandardItemModel?](#目录 @TOC 前言 一、QStandardItemModel初步介绍 二、基本功能 1.创建 2.基本属性与方法 三、何时使用 QStandardItemModel? 四、何时避免使用 QStandardItemModel?)
- [四、何时避免使用 QStandardItemModel?](#目录 @TOC 前言 一、QStandardItemModel初步介绍 二、基本功能 1.创建 2.基本属性与方法 三、何时使用 QStandardItemModel? 四、何时避免使用 QStandardItemModel?)
前言
本文主要介绍的是使用代码生成的情况下对控件的介绍,包括拥有的功能及能修改的样式,也会说明在qtdesiner拖拽控件生成和使用代码生成控件的区别(如果有的话,遇到了的会说),此版本不属于最终版本,以后遇到什么新奇的点会继续更新!本文基于QT官方的文档进行的编写,QT版本为qt 5.14.0,编写环境为Windows11。不得不说官方文档真是个好东西,有时候有些不会的上去一看就能有灵感解决了,可惜没有中文版本的。
一、QStandardItemModel初步介绍
QStandardItemModel 是 QAbstractItemModel的一个具体实现。它的核心思想是使用 QStandardItem对象来存储和管理数据。每个 QStandardItem代表模型中的一个数据项(单元格),它可以存储数据(通过角色)、设置标志(可编辑、可选等)、拥有子项(构建树结构)等。
核心优势 :
1.简单易用 : 相比直接继承 QAbstractItemModel并实现所有纯虚函数,使用 QStandardItemModel要简单得多。你只需要创建 QStandardItem对象并填充到模型中即可。
2.内置功能 : 它自动处理了数据变化通知(dataChanged信号)、结构变化通知(行/列插入删除的信号)等繁琐工作。你修改 QStandardItem的属性,模型会自动发出相应信号通知视图更新。
3.灵活性 : 非常适合表示表格数据(二维)和树状数据(层次结构)。
4.集成 QStandardItem: QStandardItem本身功能强大,可以存储多种类型的数据(文本、图标、颜色、字体等),设置各种属性(对齐、背景、前景、勾选状态等)。
二、基本功能
1.创建
cpp
// 创建一个空模型,可以稍后设置行列
QStandardItemModel *model = new QStandardItemModel(parent);
// 创建时指定初始行数和列数
QStandardItemModel *model = new QStandardItemModel(rows, columns, parent);
2.基本属性与方法
1)设置表头
cpp
// 设置水平表头标签 (列名)
model->setHorizontalHeaderLabels(QStringList() << "Name" << "Age" << "Department");
// 设置垂直表头标签 (行名,较少用)
model->setVerticalHeaderLabels(QStringList() << "Row 1" << "Row 2");
// 获取水平表头项 (QStandardItem*),可以进一步设置其属性(字体、颜色等)
QStandardItem *headerItem = model->horizontalHeaderItem(column);
headerItem->setTextAlignment(Qt::AlignCenter);
headerItem->setBackground(QBrush(Qt::lightGray));
2)创建数据项()
cpp
// 创建一个包含文本的项
QStandardItem *itemName = new QStandardItem("Alice");
// 创建一个包含文本和图标的项
QStandardItem *itemWithIcon = new QStandardItem(QIcon(":/images/user.png"), "Bob");
// 创建一个可勾选的项
QStandardItem *checkableItem = new QStandardItem("Task Complete");
checkableItem->setCheckable(true);
checkableItem->setCheckState(Qt::Checked); // 或 Qt::Unchecked
3)设置项到模型
cpp
// 设置单个项到指定位置 (行, 列)
model->setItem(row, column, item);
// 设置整行数据 (一个 QStandardItem 列表代表一行中的各列)
QList<QStandardItem*> rowItems;
rowItems << new QStandardItem("Alice") << new QStandardItem("28") << new QStandardItem("Engineering");
model->appendRow(rowItems); // 添加到末尾
model->insertRow(row, rowItems); // 插入到指定行
// 设置整列数据 (较少用)
QList<QStandardItem*> columnItems;
// ... 填充列数据 ...
model->appendColumn(columnItems);
model->insertColumn(column, columnItems);
4)获取项
cpp
// 获取指定位置的项 (行, 列)
QStandardItem *item = model->item(row, column);
// 获取水平表头项 (列)
QStandardItem *headerItem = model->horizontalHeaderItem(column);
// 获取垂直表头项 (行)
QStandardItem *vHeaderItem = model->verticalHeaderItem(row);
5)操作行和列
cpp
// 插入行
model->insertRow(row); // 插入空行
model->insertRow(row, listOfItems); // 插入带数据的行
// 插入列
model->insertColumn(column); // 插入空列
model->insertColumn(column, listOfItems); // 插入带数据的列 (每项代表该列的一行)
// 追加行/列
model->appendRow(listOfItems);
model->appendColumn(listOfItems);
// 删除行/列
model->removeRow(row);
model->removeRows(row, count); // 删除从 row 开始的 count 行
model->removeColumn(column);
model->removeColumns(column, count); // 删除从 column 开始的 count 列
// 获取行/列数
int rows = model->rowCount();
int cols = model->columnCount();
int colsForRow = model->rowCount(parentIndex); // 对于树状结构,获取父节点下的行数
6)构建树状结构 (层次数据)
cpp
// 创建父项
QStandardItem *parentItem = model->invisibleRootItem(); // 获取模型的根项 (不可见)
// 或者创建一个顶级项
QStandardItem *topLevelItem = new QStandardItem("Departments");
// 创建子项
QStandardItem *childItem1 = new QStandardItem("Engineering");
QStandardItem *childItem2 = new QStandardItem("Marketing");
// 将子项添加到父项下 (作为一行)
parentItem->appendRow(childItem1);
parentItem->appendRow(childItem2);
// 或者 topLevelItem->appendRow(childItem1);
// 也可以添加一整行子项到父项下
QList<QStandardItem*> childRow;
childRow << new QStandardItem("Alice") << new QStandardItem("Developer");
parentItem->appendRow(childRow); // parentItem 下新增一行,包含两列
// 获取父项的子项
QStandardItem *firstChild = parentItem->child(row, column); // 获取指定位置的子项
int childCount = parentItem->rowCount(); // 获取子项行数 (直接子节点数)
// 获取项的父项
QStandardItem *parentOfChild = childItem1->parent();
7)访问和修改项数据 (QStandardItem的接口)
cpp
// 设置/获取文本 (DisplayRole)
item->setText("New Name");
QString name = item->text();
// 设置/获取图标 (DecorationRole)
item->setIcon(QIcon(":/images/icon.png"));
QIcon icon = item->icon();
// 设置/获取字体 (FontRole)
QFont boldFont;
boldFont.setBold(true);
item->setFont(boldFont);
QFont usedFont = item->font();
// 设置/获取文本对齐 (TextAlignmentRole)
item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
Qt::Alignment align = item->textAlignment();
// 设置/获取背景色 (BackgroundRole)
item->setBackground(QBrush(Qt::yellow));
QBrush bgBrush = item->background();
// 设置/获取前景色 (文本颜色, ForegroundRole)
item->setForeground(QBrush(Qt::red));
QBrush fgBrush = item->foreground();
// 设置/获取勾选状态和是否可勾选 (CheckStateRole, ItemIsUserCheckable flag)
item->setCheckable(true);
item->setCheckState(Qt::Checked); // Qt::Unchecked, Qt::PartiallyChecked
bool isChecked = (item->checkState() == Qt::Checked);
bool isCheckable = item->isCheckable();
// 设置/获取是否可编辑 (ItemIsEditable flag)
item->setEditable(false);
bool editable = item->isEditable();
// 设置/获取是否启用 (ItemIsEnabled flag)
item->setEnabled(false);
bool enabled = item->isEnabled();
// 设置/获取是否可选 (ItemIsSelectable flag)
item->setSelectable(false); // 注意:通常通过 flags() 设置,但 QStandardItem 提供了这个便捷方法
bool selectable = item->isSelectable();
// 设置/获取工具提示 (ToolTipRole)
item->setToolTip("This is an important item");
QString tip = item->toolTip();
// 设置/获取状态提示 (StatusTipRole)
item->setStatusTip("Shows in status bar");
QString statusTip = item->statusTip();
// 设置/获取自定义数据 (使用 Qt::UserRole 或更高)
item->setData(QVariant(42), Qt::UserRole); // 存储一个整数
item->setData(QVariant("Custom Info"), Qt::UserRole + 1); // 存储一个字符串
int customInt = item->data(Qt::UserRole).toInt();
QString customStr = item->data(Qt::UserRole + 1).toString();
// 获取项的标志 (flags)
Qt::ItemFlags flags = item->flags();
8)查找项
cpp
// 通过文本查找项 (精确匹配,遍历所有项)
QList<QStandardItem*> foundItems = model->findItems("Alice", Qt::MatchExactly);
// 通过文本查找项 (匹配开头、包含、正则等,Qt::MatchFlag)
QList<QStandardItem*> foundStartsWith = model->findItems("A", Qt::MatchStartsWith);
// 查找指定项所在的行和列 (需要知道父项)
QStandardItem *parentItem = ...; // 父项 (或 invisibleRootItem())
int row = item->row();
int column = item->column();
9)排序
cpp
// 启用视图排序 (最简单)
tableView->setSortingEnabled(true); // 用户点击表头即可排序
// 在代码中排序 (基于列)
model->sort(column, Qt::AscendingOrder); // 升序
model->sort(column, Qt::DescendingOrder); // 降序
// 自定义排序规则 (需要继承 QStandardItemModel 并重写 lessThan)
class MySortModel : public QStandardItemModel {
protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override {
// 获取数据进行比较,left 和 right 是同一列的不同行索引
QVariant leftData = data(left);
QVariant rightData = data(right);
// ... 实现你的比较逻辑 ...
return myCustomComparisonResult;
}
};
10)与视图连接
cpp
QTableView *tableView = new QTableView;
tableView->setModel(model); // 关键一步!
QTreeView *treeView = new QTreeView;
treeView->setModel(model); // 如果 model 是树状结构
三、何时使用 QStandardItemModel?
数据量不大: 内存中可以容纳所有 QStandardItem对象。
数据结构相对简单: 表格或树状结构。
需要快速开发: 不想花费精力实现完整的 QAbstractItemModel。
需要灵活设置单元格属性: QStandardItem提供了丰富的属性设置接口。
四、何时避免使用 QStandardItemModel?
数据量巨大 (百万级): 创建和管理大量 QStandardItem对象会消耗大量内存和 CPU,性能会成为瓶颈。此时应使用自定义的 QAbstractItemModel(如基于 QAbstractTableModel),实现按需提供数据的 data()函数。
数据源特殊: 数据来自数据库、网络或其他复杂来源,直接映射到 QStandardItem不方便或不高效。
需要极致的性能优化。
本次分享就到这里了,如果有什么错误的话请指正,或者有什么疑问的,也可以在评论区一起探讨!