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

Qt model/view 理解01

在 Qt 中对数据处理主要有两种方式:1)直接对包含数据的的数据项 item 进行操作,这种方法简单、易操作,现实方式单一的缺点,特别是对于大数据或在不同位置重复出现的数据必须依次对其进行操作,如果现实方式改变,则在改动程序过程中还需对数据进行重新编码操作,费工费资源。2)采用 model/view 模型,将数据 -- 模型 -- 视图三者串起来,通过约定的接口保证数据的正确显示和显示方式的多样性,当需要重新调整显示时,只需修改视图,保证接口不变,即可以新 view 显示数据。

1/2 两种处理数据方式:

视图与数据绑定在一起:

视图与数据隔离:

在此,我主要介绍第二种模型:model/view模式,在此以QAbstractTableModel/QTableView 为例。

如果是只读模式,model 只要重写以下三个方法:

//a方法:返回模型行数。
int rowCount(const QModelIndex &parent) const; //b方法:返回模型列数。
int columnCount(const QModelIndex &parent) const; //c方法:返回index项的role角色的数据。其中index项中可以有多个角色,每个角色都可以有一个数据。
QVariant data(const QModelIndex &index, int role) const;

如果用户要能够编辑数据(编辑模式),model 还需要重写以下两个方法:

//d方法:设置模型中项的内容。
bool QAbstractItemModel::setData(const QModelIndex & index, const QVariant & value, int role= Qt::EditRole);//e方法:返回项的编辑形式,默认情况下只有ItemIsSelectable和ItemIsEnabled,如果要可编辑,需要
//添加ItemIsEditable属性。
Qt::ItemFlags QAbstractTableModel::flags(const QModelIndex & index) const

其中 a/b/c 方法为纯虚函数(pure virtual method),继承的类必须由 coder 自己实现此方法。d/e 方法为虚函数(virtual),coder 在继承了此方法,实现自定义内容后可直接调用基类方法。

在此我们以《c++ gui programming with Qt4》中的 trackEditor 例子作一讲解。

class MyTableModel : public QAbstractTableModel
{
public:explicit MyTableModel(QList<Track>* tracks, QWidget *parent = 0);virtual int rowCount(const QModelIndex &parent) const;virtual int columnCount(const QModelIndex &parent) const;virtual QVariant data(const QModelIndex &index, int role) const;virtual QVariant headerData(int section,Qt::Orientation orientation,int role) const;virtual Qt::ItemFlags flags(const QModelIndex &index) const;virtual bool setData(const QModelIndex &index, const QVariant &value, int role);private:QList<Track>* pTracks;
};

其中 “QList<Track>* tracks” 是用来保存 model 所显示的数据集合,在 model 初始化时被赋值,根据 data 方法的算法调用其中数据显示。

MyTableModel::MyTableModel(QList<Track>* tracks, QWidget *parent)
{Q_UNUSED(parent);pTracks = tracks;
}

构造函数对 tracks 进行赋值。

int MyTableModel::rowCount(const QModelIndex &parent) const
{Q_UNUSED(parent);return pTracks->count();
}int MyTableModel::columnCount(const QModelIndex &parent) const
{Q_UNUSED(parent);return 2;
}

以上 2 个方法返回 model 的行 / 列数,因为 tracks 中的数据量不确定,所以直接返回其 count 方法,保证每次都是最新值;

QVariant MyTableModel::data(const QModelIndex &index, int role) const
{if ( !index.isValid()) {return QVariant();}if (Qt::DisplayRole == role || Qt::EditRole == role) {if (0 == index.column()) {return pTracks->at(index.row()).getTitle();} else if (1 == index.column()) {return pTracks->at(index.row()).getDuration();}}return QVariant();
}

根据数据类型和所在列,返回不同的数据信息,当 index 都不属于以上两种情况时,返回 QVariant 对象。EditRole 保证了当用户编辑数据时,数据显示的是被选中模式而不是直接消失。

bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{if ( !index.isValid()) {return false;}if (Qt::EditRole == role) {(*pTracks)[index.row()].setTitle(value.toString());emit dataChanged(index, index);return true;} else {return QAbstractTableModel::setData(index, value, role);}
}

根据 coder 处理和传入角色,设置 index 处项的值及 tracks 中对应处的数据并更新 index 的数据显示。当传入数据 coder 不处理时,则直接调用基类方法处理,再辞没有特别指明第几列进行编辑,因为是后面通过 flags 方法来设定了可编辑的列,故此处不用再特别指明。在此请注意,setData 方法是判断的是 Qt::EditRole 角色,data 方法是 Qt::DisplayRole,但是保存、读取的都是 tracks,这正是 coder 要注意的,在不同的过程时,程序所处于的角色不同,但是都操作同样的数据库(tracks),这点要注意。

Qt::ItemFlags MyTableModel::flags(const QModelIndex &index) const
{if (0 == index.column()) {return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);} else {return QAbstractTableModel::flags(index);}
}

model 中每个项的处理标志位默认为(ItemIsEnabled | ItemIsSelectable),coder 可根据要求对不同属性的项进行设置。在此设定第 0 列可编辑,其余列不可编辑。

程序运行结果,分别用 TableView 和 ListView 显示相同的数据:

具体代码如下:共有 maindialg,mytablemodel,tack 三个类,一个 main 运行类。具体界面文件是由 Qt 自己生成的 ui。

track.h

#ifndef TRACK_H
#define TRACK_H#include <QString>class Track
{
public:explicit Track(const QString& title = "", int duration = 0);QString getTitle() const;int getDuration() const;void setDuration(int duration);void setTitle(QString title);private:QString mTitle;int mDuration;
};#endif // TRACK_H

track.cpp

#include "track.h"Track::Track(const QString &title, int duration) :mTitle(title),mDuration(duration)
{}QString Track::getTitle() const
{return mTitle;
}int Track::getDuration() const
{return mDuration;
}void Track::setDuration(int duration)
{mDuration = duration;
}void Track::setTitle(QString title)
{mTitle = title;
}

mytablemodel.h

#ifndef MYTABLEMODEL_H
#define MYTABLEMODEL_H#include <QWidget>
#include <QAbstractTableModel>
#include "track.h"class MyTableModel : public QAbstractTableModel
{
public:explicit MyTableModel(QList<Track>* tracks, QWidget *parent = 0);virtual int rowCount(const QModelIndex &parent) const;virtual int columnCount(const QModelIndex &parent) const;virtual QVariant data(const QModelIndex &index, int role) const;virtual QVariant headerData(int section,Qt::Orientation orientation,int role) const;virtual Qt::ItemFlags flags(const QModelIndex &index) const;virtual bool setData(const QModelIndex &index, const QVariant &value, int role);private:QList<Track>* pTracks;
};#endif // MYTABLEMODEL_H

mytablemodel.cpp

#include "mytablemodel.h"MyTableModel::MyTableModel(QList<Track>* tracks, QWidget *parent)
{Q_UNUSED(parent);pTracks = tracks;
}int MyTableModel::rowCount(const QModelIndex &parent) const
{Q_UNUSED(parent);return pTracks->count();
}int MyTableModel::columnCount(const QModelIndex &parent) const
{Q_UNUSED(parent);return 2;
}QVariant MyTableModel::data(const QModelIndex &index, int role) const
{if ( !index.isValid()) {return QVariant();}if (Qt::DisplayRole == role) {if (0 == index.column()) {return pTracks->at(index.row()).getTitle();} else if (1 == index.column()) {return pTracks->at(index.row()).getDuration();}}return QVariant();
}QVariant MyTableModel::headerData(int section,Qt::Orientation orientation,int role) const
{/*if (Qt::Vertical == orientation) {return QVariant();}*/if (Qt::DisplayRole == role && Qt::Horizontal == orientation) {switch (section) {case 0:return "first";case 1:return "second";}}return QVariant();
}Qt::ItemFlags MyTableModel::flags(const QModelIndex &index) const
{if (0 == index.column()) {return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);} else {return QAbstractTableModel::flags(index);}
}bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{if ( !index.isValid()) {return false;}if (Qt::EditRole == role) {(*pTracks)[index.row()].setTitle(value.toString());emit dataChanged(index, index);return true;} else {return QAbstractTableModel::setData(index, value, role);}
}

maindialog.h

#ifndef MAINDIALOG_H
#define MAINDIALOG_H#include <QDialog>
#include <QTableView>
#include <QListView>
#include "mytablemodel.h"namespace Ui {
class MainDialog;
}class MainDialog : public QDialog
{Q_OBJECTpublic:explicit MainDialog(QWidget *parent = 0);~MainDialog();void setTableModel(MyTableModel* model);void setListModel(MyTableModel* model);private:Ui::MainDialog *ui;QTableView* pTableView;QListView* pListView;
};#endif // MAINDIALOG_H

maindialog.cpp

#include<QGridLayout>
#include "maindialog.h"
#include "ui_maindialog.h"MainDialog::MainDialog(QWidget *parent) :QDialog(parent),ui(new Ui::MainDialog),pTableView(new QTableView(this)),pListView(new QListView(this))
{ui->setupUi(this);QVBoxLayout* layout(new QVBoxLayout(this));layout->addWidget(pTableView);layout->addWidget(pListView);setLayout(layout);setAttribute(Qt::WA_DeleteOnClose);
}MainDialog::~MainDialog()
{delete ui;
}void MainDialog::setTableModel(MyTableModel *model)
{pTableView->setModel(model);
}void MainDialog::setListModel(MyTableModel* model)
{pListView->setModel(model);
}

main.cpp

#include <QApplication>
#include "maindialog.h"
#include "track.h"
#include "mytablemodel.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);QList<Track> tracks;tracks << Track("The Flying Dutchman: Overture", 630)<< Track("The Flying Dutchman: Wie aus der Fern laengst ""vergangner Zeiten", 374)<< Track("The Flying Dutchman: Steuermann, lass die Wacht",152)<< Track("Die Walkuere: Ride of the Valkyries", 286)<< Track("Tannhaeuser: Freudig begruessen wir die edle ""Halle", 384)<< Track("Tannhaeuser: Wie Todesahnung - O du mein holder ""Abendstern", 257)<< Track("Lohengrin: Treulich gefuert ziehet dahnin", 294)<< Track("Lohengrin: In fernem Land", 383)<< Track("Die Meistersinger von Nuernberg: Overture", 543)<< Track("Die Meistersinger von Nuernberg: Verachtet mir ""die Meister nicht", 200)<< Track("Die Meistersinger von Nuernberg: Ehrt eure ""deutschen Meister", 112)<< Track("Goetterdaemmerung: Funeral Music", 469)<< Track("Tristan und Isolde: Mild und leise, wie er ""laechelt", 375);MyTableModel model(&tracks);MainDialog* w(new MainDialog(0));w->setTableModel(&model);w->setListModel(&model);w->show();return a.exec();
}

相关文章:

Qt model/view 理解01

在 Qt 中对数据处理主要有两种方式&#xff1a;1&#xff09;直接对包含数据的的数据项 item 进行操作&#xff0c;这种方法简单、易操作&#xff0c;现实方式单一的缺点&#xff0c;特别是对于大数据或在不同位置重复出现的数据必须依次对其进行操作&#xff0c;如果现实方式改…...

c与c++中的字符串

在c中&#xff0c;string本质上是一个类&#xff1b; string与char *有些区别&#xff1a; char*是一个指针&#xff1b;string是一个类&#xff0c;类内封装了char*&#xff0c;管理这一个字符串&#xff0c;是一个char*的容器 在使用string类型时&#xff0c;要加上其头文…...

Android 获取IP地址的Ping值 NetworkPingUtils

项目里需要对动态配置的Ip列表都去ping下延迟&#xff0c;取出其中最小的三个进行随机取值然后去连接&#xff0c;倒腾了一下午终于搞出来了&#xff01; 需求实现思路&#xff1a; 1.找到方法去ping IP地址&#xff1b; 2.同时去Ping&#xff0c;不能让用户等待&#xff1b…...

数据集笔记:OpenCelliD(手机基站开放数据库)

下载数据的方式可见&#xff1a;【数据获取】全球最大手机基站开源数据库 1 读取数据 import pandas as pdpd.read_csv(C:/Users/16000/Downloads/454.csv/454.csv,headerNone,names[radio,mcc,net,area,cell,unit,lon,lat,range,samples,changeable1,created1,updated,AveSi…...

Windows电脑多开器的使用心得分享

Windows电脑多开器是一种非常实用的软件工具&#xff0c;它可以让我们在同一个电脑上同时运行多个不同的应用程序&#xff0c;从而提高我们的工作和学习效率。以下是我在使用Windows电脑多开器时的一些心得分享&#xff1a; 确保你的电脑配置足够强大 多开软件需要消耗大量的…...

Android Studio实现简易计算器(带横竖屏,深色浅色模式,更该按钮颜色,selector,style的使用)

目录 前言 运行结果&#xff1a; 运行截屏&#xff08;p50e&#xff09; apk文件 源码文件 项目结构 总览 MainActivity.java drawable 更改图标的方法&#xff1a; blackbutton.xml bluebuttons.xml greybutton.xml orangebuttons.xml whitebutton.xml layout 布…...

虚拟机通过nat模式端口映射实现内网穿透

虚拟机通过nat模式端口映射实现内网穿透 1.网络状态 windows虚拟主机的IP为局域网的私有IP192.168.1.7linux的虚拟主机IP为nat的172.36.4.1062.linux修改nat模式的端口映射 3.windows宿主机防火墙添加规则,&#xff08;或者直接关闭公共网络防火墙&#xff0c;不安全&#xf…...

计算机网络(六):应用层

参考引用 计算机网络微课堂-湖科大教书匠计算机网络&#xff08;第7版&#xff09;-谢希仁 1. 应用层概述 应用层是计算机网络体系结构的最顶层&#xff0c;是设计和建立计算机网络的最终目的&#xff0c;也是计算机网络中发展最快的部分 早期基于文本的应用 (电子邮件、远程登…...

Sublime Text 4 for Mac激活下载

Sublime Text for Mac是一款适用于Mac平台的文本编辑器。它具有快速的性能和丰富的功能&#xff0c;可以帮助用户快速进行代码编写和文本编辑。 软件下载&#xff1a;Sublime Text 4 for Mac激活下载 该软件具有直观的界面和强大的功能&#xff0c;包括多行选择、代码折叠、自动…...

存在负权边的单源最短路径的原理和C++实现

负权图 此图用朴素迪氏或堆优化迪氏都会出错&#xff0c;floyd可以处理。 负环图 但floyd无法处理负权环&#xff0c;最短距离是无穷小。在环上不断循环。 经过k条边的最短距离&#xff08;可能有负权变&#xff09; 贝尔曼福特算法(bellman_ford)就是解决此问题的。 原理 …...

15-自动化测试——理论知识

目录 1.什么是自动化测试&#xff1f; 2.常见的自动化测试分类 2.1.单元测试&#xff08;Java、Python&#xff09; 2.2.接口测试&#xff08;Java、Python&#xff09; 2.3.UI测试&#xff08;移动端、网站&#xff09; 3.如何实施自动化测试&#xff1f; 4.自动化测试…...

学信息系统项目管理师第4版系列17_干系人管理

1. 项目经理和团队管理干系人的能力决定着项目的成败 2. 干系人满意度应作为项目目标加以识别和管理 3. 发展趋势和新兴实践 3.1. 识别所有干系人&#xff0c;而非在限定范围内 3.2. 确保所有团队成员都涉及引导干系人参与的活 3.3. 定期审查干系人群体&#xff0c;可与单…...

专业PDF编辑阅读工具PDF Expert mac中文特点介绍

PDF Expert mac是一款专业的PDF编辑和阅读工具。它可以帮助用户在Mac、iPad和iPhone等设备上查看、注释、编辑、填写和签署PDF文档。 PDF Expert mac软件特点 PDF编辑&#xff1a;PDF Expert提供了丰富的PDF编辑功能&#xff0c;包括添加、删除、移动、旋转、缩放、裁剪等操作…...

处理机调度的概念,层次联系以及七状态模型

1.基本概念 当有一堆任务要处理&#xff0c;但由于资源有限&#xff0c;这些事情没法同时处理。 这就需要确定某种规则来决定处理这些任务的顺序&#xff0c;这就是“调度”研究的问题。 2. 三个层次 1.高级调度&#xff08;作业调度&#xff09; 高级调度&#xff08;作业…...

PS 图层剪贴蒙版使用方法

好 我们先打开PS软件 后面我们需要接触图框工具 在学习图框工具之前 先要掌握剪贴蒙版 这里 我们先点击左上角文件 然后选择新建 我们先新建一个画布出来 然后 我们点击 箭头指向处 新建一个空白图层 点击之后 会就多出一个空白图层 我们在这里 找到 矩形选框工具 然后 …...

总结1008

今日有些小摆烂&#xff0c;在家学习的日子&#xff0c;确实感觉不如在学校好&#xff0c;无论是在时间上&#xff0c;还是在效率上。在家复习效果因人而异吧&#xff0c;都到这个关键阶段了&#xff0c;可不能掉链子啊&#xff0c;明天势必要拿出100%的状态&#xff0c;心静不…...

软件工程从理论到实践客观题汇总(头歌第九章至第十七章)

九、软件体系结构设计 1、软件体系结构设计概述 2、软件体系结构模型的表示方法 3、软件体系结构设计过程 4、设计初步的软件体系结构 5、重用已有软件资源 6、精化软件体系结构 7、设计软件部署模型 8、文档化和评审软件体系结构设计 十、软件用户界面设计 1、用户界面设计概…...

ubuntu与win之间共享文件夹

ubuntu上设置共享文件夹 第一步&#xff1a;点击【设置】或【虚拟机弹窗下面的【设置】选项】 第二步&#xff1a;进入【虚拟机设置】页面&#xff0c;点击【选项】如下图所示 第三步&#xff1a;启用共享文件&#xff1a;点击【总是启用】第四步&#xff1a;添加共享文件&…...

flink处理函数--副输出功能

背景 在flink中&#xff0c;如果你想要访问记录的处理时间或者事件时间&#xff0c;注册定时器&#xff0c;或者是将记录输出到多个输出流中&#xff0c;你都需要处理函数的帮助&#xff0c;本文就来通过一个例子来讲解下副输出 副输出 本文还是基于streaming-with-flink这本…...

Java数据结构————队列

一 、队列 在Java中&#xff0c;Queue是个接口&#xff0c;底层是通过链表实现的。 只允许在一端进行插入数据操作&#xff0c; 在另一端进行删除数据操作的特殊线性表&#xff0c; 队列具有先进先出FIFO(First In First Out) 。 入队列&#xff1a; 进行插入操作的一端称为…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...