QT基础十二、标准项模型:QStandardItemModel
目录
一、简介
二、核心功能
三、准备材料
1、所需要的action
2、将action添加进菜单栏里
3、最终样式编辑
4、准备数据文件
四、项目代码
1、需要用到的头文件与变量
2、初始化组件
3、打开txt文件,并导入其中数据
4、初始化standModel的数据
5、在尾部添加一行数据
6、插入一行数据
7、删除一行数据
8、预览模式,可以查看将要保存的状态
9、保存文件
10、将表格内的内容居中
11、 将表格内的内容居左
12、 将表格内的内容居右
13、设置字体
14、当选择的标签变化时,更新字体种类
15、运行结果
五、常用接口
QStandardItemModel
1、设置行列数 :
2、插入项:
3、获取项:
4、清除模型:
QStandardItem
1、设置文本:
2、设置图标:
3、设置子项 :
4、设置用户数据:
一、简介
在 Qt 框架中,标准项模型(Standard Item Model) 是一种通用的数据模型,用于表示树形或列表结构的数据。它是 QStandardItemModel
类的实现,属于 Qt 的模型-视图架构的一部分。标准项模型提供了一种简单而灵活的方式来存储和操作数据,并与视图组件(如 QTreeView
、QListView
或 QTableView
)结合使用。
二、核心功能
-
模型-视图架构 :
- Qt 的模型-视图架构将数据(模型)与用户界面(视图)分离。
- 模型负责管理数据,视图负责显示数据,两者通过信号槽机制进行交互。
QStandardItemModel
是一个实现了QAbstractItemModel
接口的具体模型类。
-
标准项模型的特点 :
- 它是一个通用的、可扩展的数据模型,支持树形结构和表格结构。
- 数据项由
QStandardItem
对象表示,每个项可以包含文本、图标、工具提示等信息。 - 支持动态添加、删除和修改数据项。
-
适用场景 :
- 需要快速构建简单的树形或表格视图。
- 数据量较小且不需要复杂的自定义逻辑。
- 适合原型开发或小型项目。
三、准备材料
注:QT的学习需要许多图片资源,如果你们缺少图片资源,建议去爱给网下载,或者让AI生成
准备如上图片,有的是我从网上找的,有的是我用ai生成的
1、所需要的action
2、将action添加进菜单栏里
3、最终样式
4、准备数据文件
一个txt文件,我这里用的是我大一的C语言作业的文件,随便弄一些数据就行
四、项目代码
1、需要用到的头文件与变量
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <QFileDialog>
#include <QTextStream>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_actionOpen_triggered();
void on_actionAdd_triggered();
void on_actionInsert_triggered();
void on_actionDel_triggered();
void on_actionSee_triggered();
void on_actionSave_triggered();
void on_actionCenter_triggered();
void on_actionLeft_triggered();
void on_actionRight_triggered();
void on_actionBold_triggered(bool checked);
void onSelectModelCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous);
void on_actionItalic_triggered(bool checked);
void on_actionUnderLine_triggered(bool checked);
private:
void initUI();
void initModel(QStringList lineList);
private:
Ui::MainWindow *ui;
QStandardItemModel* standModel;
QItemSelectionModel* selectModel;
};
#endif // MAINWINDOW_H
2、初始化组件
void MainWindow::initUI()
{
// 创建一个标准项模型(QStandardItemModel),并指定父对象为当前窗口(this)
// 初始行列数设置为 0,表示模型为空
standModel = new QStandardItemModel(0, 0, this);
// 创建一个选择模型(QItemSelectionModel),并将其与标准项模型关联
// 选择模型用于管理用户在视图中的选择状态
selectModel = new QItemSelectionModel(standModel);
// 将标准项模型设置为 tableView 的数据模型
// 这样 tableView 就可以显示和操作标准项模型中的数据
ui->tableView->setModel(standModel);
// 将选择模型设置为 tableView 的选择模型
// 这样 tableView 的选择操作(如点击、拖拽)会被记录到选择模型中
ui->tableView->setSelectionModel(selectModel);
// 设置 tableView 的选择模式为“扩展选择”(ExtendedSelection)
// 扩展选择允许用户通过按住 Ctrl 或 Shift 键进行多选
ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
//当选定的item改变时,触发槽函数
connect(selectModel, SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
this, SLOT(onSelectModelCurrentChanged(const QModelIndex &, const QModelIndex &)));
}
3、打开txt文件,并导入其中数据
void MainWindow::on_actionOpen_triggered()
{
// 打开一个文件选择对话框,允许用户选择一个文件
QString fileName = QFileDialog::getOpenFileName(
this, // 父窗口指针,指定对话框的父窗口
"打开一个文件", // 对话框标题,提示用户操作的目的
QCoreApplication::applicationDirPath(), // 默认打开的目录路径,这里是程序所在目录
"文本数据文件(*.txt);;所有文件(*.*)"); // 文件过滤器,限制或分类显示的文件类型
// 如果用户取消了文件选择(返回空字符串),直接退出函数
if (fileName.isEmpty()) {
return;
}
//清除掉上一个文件的残余
standModel->clear();
ui->plainTextEdit->clear();
// 创建 QFile 对象以操作选中的文件
QFile file(fileName);
// 尝试以只读和文本模式打开文件
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
// 如果文件无法打开(如权限不足或文件不存在),直接退出函数
return;
}
// 创建 QTextStream 对象,用于从文件中读取文本内容
QTextStream stream(&file);
// 定义一个字符串列表,用于存储文件的每一行内容
QStringList lineList;
// 循环读取文件的每一行内容
while (!stream.atEnd()) { // 注意:原代码中的条件 `stream.atEnd()` 是错误的,应改为 `!stream.atEnd()`
QString line = stream.readLine(); // 读取一行文本
lineList.append(line); // 将读取的行添加到字符串列表中
ui->plainTextEdit->appendPlainText(line); // 将读取的行追加到 plainTextEdit 中显示
}
// 关闭文件
file.close();
// 调用 initModel 函数,将读取的文件内容传递给模型进行初始化
initModel(lineList);
}
4、初始化standModel的数据
void MainWindow::initModel(QStringList lineList)
{
// 获取文件的第一行作为表头
QString headLine = lineList[0];
// 使用正则表达式分割字符串,提取表头字段
// QRegExp("\\s+") 匹配一个或多个空白字符(包括空格、制表符等)
// QString::SkipEmptyParts 忽略分割后产生的空字符串
QStringList tableHead = headLine.split(QRegExp("\\s+"), QString::SkipEmptyParts);
// 将分割后的表头字段设置为标准项模型的水平表头标签
standModel->setHorizontalHeaderLabels(tableHead);
// 遍历文件内容的其余行(从第二行开始)
for (int i = 1; i < lineList.count(); i++) {
// 对每一行使用正则表达式分割字符串,提取数据字段
auto itemStrList = lineList[i].split(QRegExp("\\s+"), QString::SkipEmptyParts);
// 获取当前行的数据字段数量
int cols = itemStrList.count();
// 创建一个 QList 存储当前行的 QStandardItem 对象
QList<QStandardItem*> items;
// 遍历当前行的前 (cols - 1) 个字段,创建对应的 QStandardItem 并添加到列表中
for (int j = 0; j < cols - 1; j++) {
QStandardItem* item = new QStandardItem(itemStrList[j]);
items.append(item);
}
// 创建一个特殊的 QStandardItem,用于表示“是否毕业”字段
QStandardItem* item = new QStandardItem("是否毕业");
// 设置该字段为可勾选状态
item->setCheckable(true);
// 根据最后一列的值("是" 或 "否")设置复选框的状态
itemStrList[cols - 1] == "是" ?
item->setCheckState(Qt::Checked) :
item->setCheckState(Qt::Unchecked);
// 将“是否毕业”字段添加到当前行的项列表中
items.append(item);
// 将当前行的所有项添加到标准项模型中
standModel->appendRow(items);
}
}
5、在尾部添加一行数据
void MainWindow::on_actionAdd_triggered()
{
// 创建一个 QList 存储新行的所有 QStandardItem 对象
QList<QStandardItem*> items;
// 遍历模型的列数(除最后一列外),为每列创建一个默认值为“未初始化”的项
for (int i = 0; i < standModel->columnCount() - 1; i++) {
QStandardItem* item = new QStandardItem("未初始化");
items.append(item);
}
// 创建最后一列的项,表示“是否毕业”,并设置为可勾选状态,默认未勾选
QStandardItem* item = new QStandardItem("是否毕业");
item->setCheckable(true); // 设置为可勾选
item->setCheckState(Qt::Unchecked); // 默认未勾选
// 将最后一列的项添加到列表中
items.append(item);
// 将新行的所有项添加到标准项模型的末尾
standModel->appendRow(items);
// 清除当前的选择状态
selectModel->clearSelection();
// 获取新添加行的第一列索引,并将其设置为当前选择
auto index = standModel->index(standModel->rowCount() - 1, 0);
selectModel->setCurrentIndex(index, QItemSelectionModel::Select);
}
6、插入一行数据
void MainWindow::on_actionInsert_triggered()
{
// 创建一个 QList 存储插入行的所有 QStandardItem 对象
QList<QStandardItem*> items;
// 遍历模型的列数(除最后一列外),为每列创建一个默认值为“未初始化”的项
for (int i = 0; i < standModel->columnCount() - 1; i++) {
QStandardItem* item = new QStandardItem("未初始化");
items.append(item);
}
// 创建最后一列的项,表示“是否毕业”,并设置为可勾选状态,默认未勾选
QStandardItem* item = new QStandardItem("是否毕业");
item->setCheckable(true); // 设置为可勾选
item->setCheckState(Qt::Unchecked); // 默认未勾选
// 将最后一列的项添加到列表中
items.append(item);
// 获取当前选中的索引
auto index = selectModel->currentIndex();
// 在当前选中行的位置插入新行
standModel->insertRow(index.row(), items);
// 清除当前的选择状态
selectModel->clearSelection();
// 将插入行设置为当前选择
selectModel->setCurrentIndex(index, QItemSelectionModel::Select);
}
7、删除一行数据
void MainWindow::on_actionDel_triggered()
{
// 获取当前选中的索引
auto index = selectModel->currentIndex();
// 如果当前选中的是最后一行,则直接删除该行
if (index.row() == standModel->rowCount() - 1) {
standModel->removeRow(index.row());
} else {
// 如果不是最后一行,则删除当前行,并保持选择状态不变
standModel->removeRow(index.row());
selectModel->setCurrentIndex(index, QItemSelectionModel::Select);
}
}
8、预览模式,可以查看将要保存的状态
void MainWindow::on_actionSee_triggered()
{
// 清空 plainTextEdit 控件中的内容,以便显示新的数据
ui->plainTextEdit->clear();
// 获取 standModel 模型中的行数和列数
int row = standModel->rowCount(); // 获取模型的总行数
int col = standModel->columnCount(); // 获取模型的总列数
QString str;
// 遍历模型的所有列,获取表头的内容
for(int i = 0; i < col; i++) {
// 获取第 i 列的表头项
auto item = standModel->horizontalHeaderItem(i);
// 将表头项的文本添加到字符串中,并用制表符(\t)分隔
str += item->text() + "\t";
}
// 将表头信息追加到 plainTextEdit 控件中
ui->plainTextEdit->appendPlainText(str);
// 遍历模型的所有行(从第 1 行开始,跳过表头)
for(int i = 1; i < row; i++) {
// 初始化一个空字符串,用于存储当前行的数据
str = "";
// 遍历当前行的所有列(除最后一列外)
for(int j = 0; j < col - 1; j++) {
// 获取第 i 行、第 j 列的单元格数据
auto item = standModel->item(i, j);
// 将单元格的文本添加到字符串中,并用制表符(\t)分隔
str += item->text() + "\t";
}
// 处理最后一列的数据(假设最后一列是复选框)
if(standModel->item(i, col - 1)->checkState() == Qt::Checked) {
// 如果复选框被选中,则在字符串中添加 "是"
str += "是\t";
} else {
// 如果复选框未被选中,则在字符串中添加 "否"
str += "否\t";
}
// 将当前行的数据追加到 plainTextEdit 控件中
ui->plainTextEdit->appendPlainText(str);
}
}
9、保存文件
void MainWindow::on_actionSave_triggered()
{
//选择保存文件的完整路径
QString fileName = QFileDialog::getSaveFileName(this,
"保存文件",
QCoreApplication::applicationDirPath(),
"文本数据文件(*.txt);;所有文件(*.*)");
QFile file(fileName);
if(!file.open(QIODevice::ReadWrite |
QIODevice::Text |
QIODevice::Truncate))
{
return;
}
QTextStream stream(&file);
QString str;
// 获取 standModel 模型中的行数和列数
int row = standModel->rowCount(); // 获取模型的总行数
int col = standModel->columnCount(); // 获取模型的总列数
// 遍历模型的所有列,获取表头的内容
for(int i = 0; i < col; i++) {
// 获取第 i 列的表头项
auto item = standModel->horizontalHeaderItem(i);
// 将表头项的文本添加到字符串中,并用制表符(\t)分隔
str += item->text() + "\t\t";
}
stream << str << "\n";
// 遍历模型的所有行(从第 1 行开始,跳过表头)
for(int i = 1; i < row; i++) {
// 初始化一个空字符串,用于存储当前行的数据
str = "";
// 遍历当前行的所有列(除最后一列外)
for(int j = 0; j < col - 1; j++) {
// 获取第 i 行、第 j 列的单元格数据
auto item = standModel->item(i, j);
// 将单元格的文本添加到字符串中,并用制表符(\t)分隔
str += item->text() + "\t\t";
}
// 处理最后一列的数据(假设最后一列是复选框)
if(standModel->item(i, col - 1)->checkState() == Qt::Checked) {
// 如果复选框被选中,则在字符串中添加 "是"
str += "是\t";
} else {
// 如果复选框未被选中,则在字符串中添加 "否"
str += "否\t";
}
stream << str << "\n";
}
file.close();
}
10、将表格内的内容居中
// 当用户触发“居中对齐”操作时调用此函数
void MainWindow::on_actionCenter_triggered()
{
// 检查是否有选中的项,如果没有选中任何项,则直接返回,不做任何操作
if (!selectModel->hasSelection()) {
return;
}
// 获取当前选中的所有索引(即用户在界面中选中的单元格)
auto indexList = selectModel->selectedIndexes();
// 遍历选中的索引列表
for (auto& index : indexList) {
// 根据索引从标准模型中获取对应的项(QStandardItem)
auto* item = standModel->itemFromIndex(index);
// 设置该项的文本对齐方式为居中对齐
item->setTextAlignment(Qt::AlignCenter);
}
}
11、 将表格内的内容居左
// 当用户触发“左对齐”操作时调用此函数
void MainWindow::on_actionLeft_triggered()
{
// 检查是否有选中的项,如果没有选中任何项,则直接返回,不做任何操作
if (!selectModel->hasSelection()) {
return;
}
// 获取当前选中的所有索引
auto indexList = selectModel->selectedIndexes();
// 遍历选中的索引列表
for (auto& index : indexList) {
// 根据索引从标准模型中获取对应的项
auto* item = standModel->itemFromIndex(index);
// 设置该项的文本对齐方式为左对齐,并垂直方向居中对齐
item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
}
}
12、 将表格内的内容居右
// 当用户触发“右对齐”操作时调用此函数
void MainWindow::on_actionRight_triggered()
{
// 检查是否有选中的项,如果没有选中任何项,则直接返回,不做任何操作
if (!selectModel->hasSelection()) {
return;
}
// 获取当前选中的所有索引
auto indexList = selectModel->selectedIndexes();
// 遍历选中的索引列表
for (auto& index : indexList) {
// 根据索引从标准模型中获取对应的项
auto* item = standModel->itemFromIndex(index);
// 设置该项的文本对齐方式为右对齐,并垂直方向居中对齐
item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
}
}
13、设置字体
// 当用户触发“加粗”操作时调用此函数
void MainWindow::on_actionBold_triggered(bool checked)
{
// 检查是否有选中的项,如果没有选中任何项,则直接返回,不做任何操作
if (!selectModel->hasSelection()) {
return;
}
// 获取当前选中的所有索引(即用户在界面中选中的单元格)
auto indexList = selectModel->selectedIndexes();
// 遍历选中的索引列表
for (auto& index : indexList) {
// 根据索引从标准模型中获取对应的项(QStandardItem)
auto* item = standModel->itemFromIndex(index);
// 获取该项的字体
QFont font = item->font();
// 根据传入的参数 `checked` 设置字体是否加粗
font.setBold(checked);
// 将修改后的字体重新设置到该项
item->setFont(font);
}
}
// 当用户触发“斜体”操作时调用此函数
void MainWindow::on_actionItalic_triggered(bool checked)
{
// 检查是否有选中的项,如果没有选中任何项,则直接返回,不做任何操作
if (!selectModel->hasSelection()) {
return;
}
// 获取当前选中的所有索引
auto indexList = selectModel->selectedIndexes();
// 遍历选中的索引列表
for (auto& index : indexList) {
// 根据索引从标准模型中获取对应的项
auto* item = standModel->itemFromIndex(index);
// 获取该项的字体
QFont font = item->font();
// 根据传入的参数 `checked` 设置字体是否为斜体
font.setItalic(checked);
// 将修改后的字体重新设置到该项
item->setFont(font);
}
}
// 当用户触发“下划线”操作时调用此函数
void MainWindow::on_actionUnderLine_triggered(bool checked)
{
// 检查是否有选中的项,如果没有选中任何项,则直接返回,不做任何操作
if (!selectModel->hasSelection()) {
return;
}
// 获取当前选中的所有索引
auto indexList = selectModel->selectedIndexes();
// 遍历选中的索引列表
for (auto& index : indexList) {
// 根据索引从标准模型中获取对应的项
auto* item = standModel->itemFromIndex(index);
// 获取该项的字体
QFont font = item->font();
// 根据传入的参数 `checked` 设置字体是否带有下划线
font.setUnderline(checked);
// 将修改后的字体重新设置到该项
item->setFont(font);
}
}
14、当选择的标签变化时,更新字体种类
// 当选择模型的当前选中项发生变化时调用此函数
void MainWindow::onSelectModelCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous)
{
// 检查当前选中的索引是否有效(即是否存在有效的选中项)
if (current.isValid()) {
// 根据当前选中的索引从标准模型中获取对应的项(QStandardItem)
auto* item = standModel->itemFromIndex(current);
// 获取该项的字体,并根据字体属性更新界面上的操作按钮状态
// 设置“加粗”操作按钮的状态为字体的加粗属性(true 或 false)
ui->actionBold->setChecked(item->font().bold());
// 设置“斜体”操作按钮的状态为字体的斜体属性(true 或 false)
ui->actionItalic->setChecked(item->font().italic());
// 设置“下划线”操作按钮的状态为字体的下划线属性(true 或 false)
ui->actionUnderLine->setChecked(item->font().underline());
}
}
15、运行结果
五、常用接口
以下是 QStandardItemModel
和 QStandardItem
的一些常用方法:
QStandardItemModel
1、设置行列数 :
void setRowCount(int rows);
void setColumnCount(int columns);
2、插入项:
void appendRow(QStandardItem *item);
void insertRow(int row, QStandardItem *item);
3、获取项:
QStandardItem *item(int row, int column = 0) const;
4、清除模型:
void clear();
QStandardItem
1、设置文本:
void setText(const QString &text);
QString text() const;
2、设置图标:
void setIcon(const QIcon &icon);
QIcon icon() const;
3、设置子项 :
void appendRow(QStandardItem *item);
void appendRows(const QList<QStandardItem *> &items);
4、设置用户数据:
void setData(const QVariant &value, int role = Qt::UserRole + 1);
QVariant data(int role = Qt::UserRole + 1) const;