【嵌入式——QT】Model/View

【嵌入式——QT】Model/View

  • 基本原理
  • 数据模型
  • 视图组件
  • 代理
  • Model/View结构的一些概念
  • QFileSystemModel
  • QStringListModel
  • QStandardItemModel
  • 自定义代理

基本原理

GUI应用程序的一个很重要的功能是由用户在界面上编辑和修改数据,典型的如数据库应用程序,数据库应用程序中,用户在界面上执行各种操作,实际上是修改了界面组件所关联的数据库内的数据。将界面组件与所编辑的数据分离开来,又通过数据源的方式连接起来,是处理界面与数据的一种较好的方式,Qt使用Model/View结构来处理这种关系。

数据模型

QAbstractItemModel

  • QAbstractListModel:QStringListModel,处理字符串列表数据的数据模型类;
  • QAbstractProxyModel:QSortFilterProxyModel,提供排序和过滤功能的数据模型类;
  • QAbstractTableModel:QSqlQueryModel,数据库SQL查询结构的数据模型类;QSqlTableModel,用于数据库的一个数据表的数据模型类;QSqlRelationalTableModel,关系型数据表的数据模型类;
  • QStandardItemModel:每个项数据可以使任何数据类型;
  • QFileSystemModel:文件系统的数据模型类;

视图组件

  • QListView:用于显示单列的列表数据,适用于一维数据的操作;
  • QTreeView:用于显示树状结构数据,适用于树状结构数据的操作;
  • QTableView:用于显示表格状数据,适用于二维表格型数据的操作;
  • QColumnView:用多个QListView显示树状层次结构,树状结构的一层用一个QListView显示;
  • QHeaderView:提供行表头或列表头的视图组件,如QTableView的行表头和列表头;

代理

代理(Delegate)就是在视图组件上为编辑数据提供编辑器,如在表格组件中编辑一个单元格的数据时,缺省是使用一个QLineEdit编辑框。
代理负责从数据模型获取相应的数据,然后显示在编辑器里,修改数据后,又将其保存到数据模型中。
QAbstractItemDelegate是所有代理类的基类,它不能直接使用,它的一个子类QStyledItemDelegate,是Qt的视图组件缺省使用的代理类。

Model/View结构的一些概念

基本结构
数据模型中的存储数据的基本单元都是项(item),每个项都有一个行号,一个列号,还有一个父项。
模型索引
QModelIndex表示模型索引的类,模型索引提供数据存取的一个临时指针,用于通过数据模型提取或修改数据,因为模型内部数据的结构随时可能改变,所以模型索引是临时的。
行号和列号
数据模型的基本形式是用行和列定义的表格数据,要获得一个模型索引,必须提供行号、列号、父项的模型索引。
父项
当数据模型是列表或表格时,使用行号、列号存储数据比较直观,所有数据项的父项就是顶层项,当数据模型是树状结构时,情况比较复杂,一个节点可以有父节点,也可以是其他节点的父节点,在构造数据项的模型索引时,必须指定正确的行号、列号和父节点。
项的角色
在为数据模式的一个项设置数据时,可以赋予其不同项的角色的数据。
enum ItemDataRole

  • Qt::DisplayRole:在视图组件中显示字符串,标准角色;
  • Qt::ToolTipRole:鼠标提示消息;
  • Qt::UserRole:可以自定义数据;

QFileSystemModel

QFileSystemModel提供了一个可用于访问本机文件系统的数据模型,QFileSystemModel和视图组件QTreeView结合使用,可以用目录树的形式显示本机上的文件系统,如同Windows的资源管理器一样,使用QFileSystemModel提供的接口函数,可以创建目录,删除目录,重命名目录,可以获得文件名称、目录名称、文件大小等参数,还可以获得文件的详细信息。
图示
在这里插入图片描述

代码示例
ModelViewDialog.h

#ifndef MODELVIEWDIALOG_H
#define MODELVIEWDIALOG_H#include <QDialog>
#include <QFileSystemModel>namespace Ui
{class ModelViewDialog;
}class ModelViewDialog : public QDialog
{Q_OBJECTpublic:explicit ModelViewDialog(QWidget* parent = nullptr);~ModelViewDialog();
private slots:void on_treeView_clicked(const QModelIndex& index);private:Ui::ModelViewDialog* ui;QFileSystemModel* model;
};#endif // MODELVIEWDIALOG_H

ModelViewDialog.cpp

#include "ModelViewDialog.h"
#include "ui_ModelViewDialog.h"
ModelViewDialog::ModelViewDialog(QWidget* parent): QDialog(parent), ui(new Ui::ModelViewDialog)
{ui->setupUi(this);model = new QFileSystemModel(this);//QDir::currentPath() 获得本机文件系统model->setRootPath(QDir::currentPath());//设置根目录ui->treeView->setModel(model);//设置数据模型ui->listView->setModel(model);//设置数据模型ui->tableView->setModel(model);//设置数据模型connect(ui->treeView, SIGNAL(clicked(QModelIndex)), ui->listView, SLOT(setRootIndex(QModelIndex)));connect(ui->treeView, SIGNAL(clicked(QModelIndex)), ui->tableView, SLOT(setRootIndex(QModelIndex)));
}ModelViewDialog::~ModelViewDialog()
{delete ui;
}void ModelViewDialog::on_treeView_clicked(const QModelIndex& index)
{ui->checkBox->setChecked(model->isDir(index));//是否目录ui->labPath->setText(model->filePath(index));//返回节点的目录名或带路径的文件名ui->labType->setText(model->type(index));//返回描述节点类型的文字ui->labFileName->setText(model->fileName(index));//返回去除路径的文件夹名称或文件名int sz = model->size(index)/1024;//如果节点是文件,返回文件大小的字节数,如果节点是文件夹,返回0if(sz<1024) {ui->labSize->setText(QString("%1 KB").arg(sz));} else {ui->labSize->setText(QString::asprintf("%.1f MB", sz/1024.0));}
}

QStringListModel

QStringListModel用于处理字符串列表的数据模型,它可以作为QListView的数据模型,在界面上显示和编辑字符串列表。

图示
在这里插入图片描述

代码示例

QStringListModelDialog.h

#ifndef QSTRINGLISTMODELDIALOG_H
#define QSTRINGLISTMODELDIALOG_H#include <QDialog>
#include <QStringListModel>namespace Ui
{class QStringListModelDialog;
}class QStringListModelDialog : public QDialog
{Q_OBJECTpublic:explicit QStringListModelDialog(QWidget* parent = nullptr);~QStringListModelDialog();private slots:void on_pushButtonAdd_clicked();void on_pushButtonInsert_clicked();void on_pushButtonRemove_clicked();void on_pushButtonClear_clicked();void on_pushButtonShow_clicked();void on_listView_clicked(const QModelIndex& index);void on_pushButtonReset_clicked();void on_pushButtonClearText_clicked();private:Ui::QStringListModelDialog* ui;QStringListModel* model;
};#endif // QSTRINGLISTMODELDIALOG_H

QStringListModelDialog.cpp

#include "QStringListModelDialog.h"
#include "ui_QStringListModelDialog.h"
QStringListModelDialog::QStringListModelDialog(QWidget* parent): QDialog(parent), ui(new Ui::QStringListModelDialog)
{ui->setupUi(this);QStringList theStrList;theStrList<<"北京"<<"上海"<<"天津"<<"河北"<<"河南"<<"山东";model = new QStringListModel(this);//将一个字符串列表的内容作为数据模型的初始化数据内容model->setStringList(theStrList);ui->listView->setModel(model);//双击 或 选择并单击后进入编辑状态ui->listView->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);
}QStringListModelDialog::~QStringListModelDialog()
{delete ui;
}void QStringListModelDialog::on_pushButtonAdd_clicked()
{model->insertRow(model->rowCount());//在尾部插入一行QModelIndex index = model->index(model->rowCount()-1, 0);model->setData(index, "new item", Qt::DisplayRole);ui->listView->setCurrentIndex(index);//设置当前选中的行
}void QStringListModelDialog::on_pushButtonInsert_clicked()
{QModelIndex index = ui->listView->currentIndex();model->insertRow(index.row());model->setData(index, "inserted item", Qt::DisplayRole);ui->listView->setCurrentIndex(index);
}void QStringListModelDialog::on_pushButtonRemove_clicked()
{QModelIndex index = ui->listView->currentIndex();model->removeRow(index.row());
}void QStringListModelDialog::on_pushButtonClear_clicked()
{model->removeRows(0, model->rowCount());
}void QStringListModelDialog::on_pushButtonShow_clicked()
{QStringList tmpList = model->stringList();ui->plainTextEdit->clear();for(int i=0; i<tmpList.count(); i++) {ui->plainTextEdit->appendPlainText(tmpList.at(i));}
}void QStringListModelDialog::on_listView_clicked(const QModelIndex& index)
{ui->label->setText(QString::asprintf("current:row=%d,column=%d", index.row(), index.column()));
}void QStringListModelDialog::on_pushButtonReset_clicked()
{model->removeRows(0, model->rowCount());QStringList theStrList;theStrList<<"北京"<<"上海"<<"天津"<<"河北"<<"河南"<<"山东";model->setStringList(theStrList);
}void QStringListModelDialog::on_pushButtonClearText_clicked()
{ui->plainTextEdit->clear();
}

QStandardItemModel

QStandardItemModel是标准的以项数据为基础的标准数据模型类,通常与QTableView组合成Model/View结构。实现通用的二维数据的管理功能。

图示
在这里插入图片描述

代码示例
QStandardItemModelDialog.h

#ifndef QSTANDARDITEMMODELDIALOG_H
#define QSTANDARDITEMMODELDIALOG_H#include <QDialog>
#include <QLabel>#include <QStandardItemModel>
#include <QItemSelectionModel>
#define FixedColumnCount 6
namespace Ui
{class QStandardItemModelDialog;
}class QStandardItemModelDialog : public QDialog
{Q_OBJECTpublic:explicit QStandardItemModelDialog(QWidget* parent = nullptr);~QStandardItemModelDialog();void initModelFromStringList(QStringList& fFileContent);public slots:void on_currentChanged(const QModelIndex& current, const QModelIndex& previous);private slots:void on_pushButtonOpen_clicked();void on_pushButtonAdd_clicked();void on_pushButtonInsert_clicked();void on_pushButtonRemove_clicked();void on_pushButtonLeft_clicked();void on_pushButtonMid_clicked();void on_pushButtonRight_clicked();void on_pushButtonBold_clicked();void on_pushButtonSaveAs_clicked();private:Ui::QStandardItemModelDialog* ui;QStandardItemModel* model;QLabel* labCurFile;QLabel* labCellPos;QLabel* labCellText;QItemSelectionModel* theSelection;};#endif // QSTANDARDITEMMODELDIALOG_H

QStandardItemModelDialog.cpp

#include "QStandardItemModelDialog.h"
#include "ui_QStandardItemModelDialog.h"
#include <QAbstractItemView>
#include <QFileDialog>
#include <QTextStream>QStandardItemModelDialog::QStandardItemModelDialog(QWidget* parent): QDialog(parent), ui(new Ui::QStandardItemModelDialog)
{ui->setupUi(this);model = new QStandardItemModel(0, FixedColumnCount, this);theSelection = new QItemSelectionModel(model);connect(theSelection, SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(on_currentChanged(QModelIndex, QModelIndex)));ui->tableView->setModel(model);ui->tableView->setSelectionModel(theSelection);ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);
}QStandardItemModelDialog::~QStandardItemModelDialog()
{delete ui;
}void QStandardItemModelDialog::initModelFromStringList(QStringList& fFileContent)
{int rowCnt = fFileContent.count();model->setRowCount(rowCnt);QString header = fFileContent.at(0);//用一个或多个空白字符分隔  SkipEmptyParts函数会跳过任何空的部分QStringList headerList = header.split(QRegExp("\\s+"), QString::SkipEmptyParts);model->setHorizontalHeaderLabels(headerList);QStandardItem* item;QStringList tmpList;int j;for(int i=1; i<rowCnt; i++) {QString aLinText = fFileContent.at(i);tmpList = aLinText.split(QRegExp("\\s+"), QString::SkipEmptyParts);for(j=0; j<FixedColumnCount-1; j++) {item = new QStandardItem(tmpList.at(j));model->setItem(i-1, j, item);}item = new QStandardItem(headerList.at(j));item->setCheckable(true);if(tmpList.at(j) == "0") {item->setCheckState(Qt::Unchecked);} else {item->setCheckState(Qt::Checked);}model->setItem(i-1, j, item);}
}void QStandardItemModelDialog::on_currentChanged(const QModelIndex& current, const QModelIndex& previous)
{if(current.isValid()) {// labCellPos->setText(QString::asprintf("current: row=%d , col=%d", current.row(), current.column()));QStandardItem* item = model->itemFromIndex(current);// this->labCellText->setText("text:"+item->text());// QFont font = item->font();}
}void QStandardItemModelDialog::on_pushButtonOpen_clicked()
{QString curPath = QCoreApplication::applicationDirPath();QString aFileName = QFileDialog::getOpenFileName(this, u8"打开文件", curPath);if(aFileName.isEmpty()) {return;}QStringList fFileContent;QFile afile(aFileName);if(afile.open(QIODevice::ReadOnly |QIODevice::Text)) {QTextStream aStream(&afile);ui->plainTextEdit->clear();while(!aStream.atEnd()) {QString str = aStream.readLine();ui->plainTextEdit->appendPlainText(str);fFileContent.append(str);}afile.close();// labCurFile->setText("currentFile:"+aFileName);initModelFromStringList(fFileContent);}
}void QStandardItemModelDialog::on_pushButtonAdd_clicked()
{QList<QStandardItem*> itemList;QStandardItem* item;//不包含最后一列for(int i=0; i<FixedColumnCount-1; i++) {item = new QStandardItem("0");// item->setCheckable(true);itemList<<item;}QString str = model->headerData(model->columnCount()-1, Qt::Horizontal, Qt::DisplayRole).toString();item = new QStandardItem(str);item->setCheckable(true);itemList<<item;model->insertRow(model->rowCount(), itemList);QModelIndex curIndex = model->index(model->rowCount()-1, 0);theSelection->clearSelection();theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);
}void QStandardItemModelDialog::on_pushButtonInsert_clicked()
{QList<QStandardItem*> itemList;QStandardItem* item;//不包含最后一列for(int i=0; i<FixedColumnCount-1; i++) {item = new QStandardItem("0");// item->setCheckable(true);itemList<<item;}QString str = model->headerData(model->columnCount()-1, Qt::Horizontal, Qt::DisplayRole).toString();item = new QStandardItem(str);item->setCheckable(true);itemList<<item;QModelIndex curIndex = theSelection->currentIndex();int curRow = curIndex.row();model->insertRow(curRow, itemList);curIndex = model->index(curRow, 0);theSelection->clearSelection();theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);
}void QStandardItemModelDialog::on_pushButtonRemove_clicked()
{QModelIndex curIndex = theSelection->currentIndex();if(curIndex.row() == model->rowCount()-1) {model->removeRow(curIndex.row());} else {model->removeRow(curIndex.row());theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);}
}void QStandardItemModelDialog::on_pushButtonLeft_clicked()
{if(!theSelection->hasSelection()) {return;}QModelIndexList selectedIndex = theSelection->selectedIndexes();for(int i=0; i<selectedIndex.count(); i++) {QModelIndex aIndex = selectedIndex.at(i);QStandardItem* item = model->itemFromIndex(aIndex);item->setTextAlignment(Qt::AlignLeft);}
}void QStandardItemModelDialog::on_pushButtonMid_clicked()
{if(!theSelection->hasSelection()) {return;}QModelIndexList selectedIndex = theSelection->selectedIndexes();for(int i=0; i<selectedIndex.count(); i++) {QModelIndex aIndex = selectedIndex.at(i);QStandardItem* item = model->itemFromIndex(aIndex);item->setTextAlignment(Qt::AlignCenter);}
}void QStandardItemModelDialog::on_pushButtonRight_clicked()
{if(!theSelection->hasSelection()) {return;}QModelIndexList selectedIndex = theSelection->selectedIndexes();for(int i=0; i<selectedIndex.count(); i++) {QModelIndex aIndex = selectedIndex.at(i);QStandardItem* item = model->itemFromIndex(aIndex);item->setTextAlignment(Qt::AlignRight);}
}void QStandardItemModelDialog::on_pushButtonBold_clicked()
{if(!theSelection->hasSelection()) {return;}QModelIndexList selectedIndex = theSelection->selectedIndexes();for(int i=0; i<selectedIndex.count(); i++) {QModelIndex aIndex = selectedIndex.at(i);QStandardItem* item = model->itemFromIndex(aIndex);QFont font = item->font();font.setBold(Qt::Checked);item->setFont(font);}
}void QStandardItemModelDialog::on_pushButtonSaveAs_clicked()
{QString curPath = QCoreApplication::applicationDirPath();QString aFileName = QFileDialog::getSaveFileName(this, u8"选择一个文件", curPath);if(aFileName.isEmpty()) {return;}QFile file(aFileName);if(!(file.open(QIODevice::ReadWrite | QIODevice::Text| QIODevice::Truncate))) {return;}QTextStream aStream(&file);QStandardItem* item;int i, j;QString str;ui->plainTextEdit->clear();for(int i=0; i<model->columnCount(); i++) {item = model->horizontalHeaderItem(i);str = str +item->text()+"\t\t";}aStream<<str<<"\n";ui->plainTextEdit->appendPlainText(str);for(i=0; i<model->rowCount(); i++) {str="";for(j=0; j<model->columnCount()-1; j++) {item = model->item(i, j);str=str+item->text()+QString::asprintf("\t\t");}item = model->item(i, j);if(item->checkState() == Qt::Checked) {str = str+"1";} else {str = str+"0";}ui->plainTextEdit->appendPlainText(str);aStream<<str<<"\n";}
}

自定义代理

QAbstractItemDelegate是所有代理类的抽象基类,QStyledItemDelegate是视图组件使用的缺省的代理类,QItemDelegate也是类似功能的类。
QStyledItemDelegate和QItemDelegate的差别在于前者可以使用样式表设置来绘制组件,因此建议使用QStyledItemDelegate作为自定义代理类组件的基类。
无论从QStyledItemDelegate还是QItemDelegate继承设计自定义代理组件,都会必须实现这四个函数。

  1. createEditor:创建用于编辑模型数据的widget组件,如QSpinBox组件;
  2. setEditorData:从数据模型获取数据,供widget组件进行编辑;
  3. setModelData:将widget上的数据更新到数据模型;
  4. updateEditorGeometry:用于给widget组件设置一个合适的大小;

详见我之前一段时间所写的文章 文章地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/520252.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ArcGIS Pro二次开发】(84):WPF_给Combobox加点料

一、要实现的功能 在WPF中&#xff0c;一个正常的Combobox是长这样的&#xff1a; 当点击下拉框的时候&#xff0c;下拉列表就是简单的文本&#xff0c;看起来很单一。 这里我们给它加点料&#xff0c;让它变成这样&#xff1a; 就是给文本前面加个图标&#xff0c;这个图标可…

高精度减法

#include<iostream> #include<vector>using namespace std;//判断是否有A>B, bool cmp(vector<int> &A,vector<int> &B) {if(A.size()!B.size()) return A.size()>B.size();for(int iA.size()-1;i>0;i--)if(A[i]!B[i])return A[i]>…

Manz高压清洗机S11-028GCH-High Quality Cleaner 操作使用说明492页

Manz高压清洗机S11-028GCH-High Quality Cleaner 操作使用说明492页

YOLOv9(2):YOLOv9网络结构

1. 前言 本文仅以官方提供的yolov9.yaml来进行简要讲解。 讲解之前&#xff0c;还是要做一些简单的铺垫。 Slice层不做任何的操作&#xff0c;纯粹是做一个占位层。这样一来&#xff0c;在parse_model时&#xff0c;ch[n]可表示第n层的输出通道。 Detect和DDetect主要区别还…

Django cookie 与 session

Django cookie 与 session Cookie 是存储在客户端计算机上的文本文件&#xff0c;并保留了各种跟踪信息。 识别返回用户包括三个步骤&#xff1a; 服务器脚本向浏览器发送一组 Cookie。例如&#xff1a;姓名、年龄或识别号码等。浏览器将这些信息存储在本地计算机上&#xf…

JS实现chatgpt数据流式回复效果

最近高了一个简单chatgpt对话功功能&#xff0c;回复时希望流式回复&#xff0c;而不是直接显示结果&#xff0c;其实很简单&#xff0c;前端流式读取即可&#xff0c;后端SSE实现流式传输 前端用到fetch获取数据&#xff0c;然后利用reader读取 let requestId parseInt(Ma…

勾股定理的七种经典证明

据说勾股定理约有500种证明方法&#xff0c;下面介绍几种经典的证明方法。 一、切割重拼法。 顾名思义&#xff0c;就是将图形切割成其他形式的图形&#xff0c;然后通过拼图转换为另一种图形&#xff0c;这个过程中图形的面积是不变的。 “赵爽弦图”是这种方法的经典应用&…

西门子Mendix低代码资深技术顾问张戟,将出席“ISIG-低代码/零代码技术与应用发展峰会”

3月16日&#xff0c;第四届「ISIG中国产业智能大会」将在上海中庚聚龙酒店拉开序幕。本届大会由苏州市金融科技协会指导&#xff0c;企智未来科技&#xff08;LowCode低码时代、RPA中国、AIGC开放社区&#xff09;主办。大会旨在聚合每一位产业成员的力量&#xff0c;深入探索低…

腾讯云学生服务器多少钱?怎么申请?

2024年腾讯云学生服务器优惠活动「云校园」&#xff0c;学生服务器优惠价格&#xff1a;轻量应用服务器2核2G学生价30元3个月、58元6个月、112元一年&#xff0c;轻量应用服务器4核8G配置191.1元3个月、352.8元6个月、646.8元一年&#xff0c;CVM云服务器2核4G配置842.4元一年&…

学习clickhouse 集群搭建和分布式存储

为什么要用集群 使用集群的主要原因是为了提高系统的可扩展性、可用性和容错性。 可扩展性&#xff1a;当单个节点无法处理增加的负载时&#xff0c;可以通过添加更多的节点到集群来增加处理能力。这使得系统可以处理更大的数据量和更高的查询负载。可用性&#xff1a;在集群…

驱动调试第013期-G120XA驱动同步电机应用案例

概述 SINAMICS G120XA是西门子SINAMICS系列变频器的新成员&#xff0c; 功率范围覆盖0.75 kW~560 kW&#xff0c;内置风机和水泵行业应用功能&#xff0c;汇集了优异的高性能矢量控制算法&#xff0c;可以轻松的驱动风机、水泵及压缩机等负载。胜任各种应用场合&#xff0c;专…

Pycharm+Selenium WebdriverPython自动化测试

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…