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();
}

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

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

相关文章

10.1select并发服务器以及客户端

服务器&#xff1a; #include<myhead.h>//do-while只是为了不让花括号单独存在&#xff0c;并不循环 #define ERR_MSG(msg) do{\fprintf(stderr,"%d:",__LINE__);\perror(msg);\ }while(0);#define PORT 8888//端口号1024-49151 #define IP "192.168.2.5…

【16】c++设计模式——>建造者(生成器)模式

什么是建造者模式? 建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;它允许你构造复杂对象步骤分解。你可以不同的步骤中使用不同的方式创建对象&#xff0c;且对象的创建与表示是分离的。这样&#xff0c;同样的构建过程可以创建不同的表…

数据结构-快速排序-C语言实现

引言&#xff1a;快速排序作为一种非常经典且高效的排序算法&#xff0c;无论是工作还是面试中广泛用到&#xff0c;作为一种分治思想&#xff0c;需要熟悉递归思想。下面来讲讲快速排序的实现和改进。 老规矩&#xff0c;先用图解来理解一下&#xff1a;&#xff08;这里使用快…

MATLAB中syms函数使用

目录 语法 说明 示例 创建符号标量变量 创建符号标量变量的向量 创建符号标量变量矩阵 管理符号标量变量的假设 创建和评估符号函数 syms函数的作用是创建符号标量和函数&#xff0c;以及矩阵变量和函数。 语法 syms var1 ... varN syms var1 ... varN [n1 ... nM] …

指数分布优化器(EDO)(含MATLAB代码)

先做一个声明&#xff1a;文章是由我的个人公众号中的推送直接复制粘贴而来&#xff0c;因此对智能优化算法感兴趣的朋友&#xff0c;可关注我的个人公众号&#xff1a;启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法&#xff0c;经典的&#xff0c;或者是近几年…

“秋天第一只大闸蟹”背后,看见京东一体化供应链

京东似乎正在从一个大闸蟹的物流服务商、销售商&#xff0c;转变为一个大闸蟹的“供货商”。 作者|斗斗 编辑|皮爷 出品|产业家 阳澄湖连续几天的降雨&#xff0c;使得通往蟹塘的路异常难走。 长期驻扎此地的京东相关负责人蹲在蟹塘边的小路上&#xff0c;指着蟹塘说道…

【RabbitMQ 实战】08 集群原理剖析

上一节&#xff0c;我们用docker-compose搭建了一个RabbitMQ集群&#xff0c;这一节我们来分析一下集群的原理 一、基础概念 1.1 元数据 前面我们有介绍到 RabbitMQ 内部有各种基础构件&#xff0c;包括队列、交换器、绑定、虚拟主机等&#xff0c;他们组成了 AMQP 协议消息…

Cocos Creator3.8 项目实战(五)背景无限滚屏效果如何实现

在游戏中&#xff0c;我们经常会实现背景无限滚动的效果。那这些效果是怎么实现的呢&#xff1f; 原理很简单&#xff0c;就是使用多张背景图&#xff0c;每张图&#xff0c;每一帧都同时移动&#xff0c;当图移出屏幕外时&#xff0c;将其位置设置到下一张图的初始位置&#x…

【AI视野·今日NLP 自然语言处理论文速览 第四十八期】Thu, 5 Oct 2023

AI视野今日CS.NLP 自然语言处理论文速览 Thu, 5 Oct 2023 Totally 50 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Retrieval meets Long Context Large Language Models Authors Peng Xu, Wei Ping, Xianchao Wu, Lawrence McA…

[架构之路-231]:计算机硬件与体系结构 - 性能评估汇总,性能优化加速比

目录 一、计算机体系结构 二、计算机性能评估 2.1 分类方法1 2.2 分类方法2 三、常见的专项性能测试工具 3.1 浮点运算性能&#xff08;FLOPS&#xff09; 3.2 综合理论性能法 3.3 历史基准测试&#xff08;跑分软件&#xff09;&#xff1a;通过运行典型的综合性的程序…

反爬虫机制与反爬虫技术(一)

反爬虫机制与反爬虫技术一 1、网络爬虫的法律与道德问题2、反爬虫机制与反爬虫技术2.1、User-Agent伪装2.2、代理IP2.3、请求频率控制2.4、动态页面处理2.5、验证码识别3、反爬虫案例:豆瓣电影Top250爬取3.1、爬取目标3.2、库(模块)简介3.3、翻页分析3.4、发送请求3.5、提取…

【VUE·疑难问题】定义 table 中每行的高度(使用 element-UI)

一、如何定义 table 中每一行的 height &#xff1f; 1.table例子 <!-- 二、table --><div style"overflow: hidden;display: block;height: 68vh;width: 100%;"><el-table stripe show-header style"width: 100%" :data"tableData&q…

mysql面试题20:有哪些合适的分布式主键方案

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:有哪些合适的分布式主键方案? UUID:UUID通常是由一个二进制的128位整数表示,可以保证全局的唯一性。在Java中,可以通过UUID类生成一个UUID。例…

Hadoop伪分布式环境搭建

什么是Hadoop伪分布式集群&#xff1f; Hadoop 伪分布式集群是一种在单个节点上模拟分布式环境的配置&#xff0c;用于学习、开发和测试 Hadoop 的功能和特性。它提供了一个简化的方式来体验和熟悉 Hadoop 的各个组件&#xff0c;而无需配置和管理一个真正的多节点集群。 在 Ha…

定量活性关系(QSAR)是什么?定量结构-性质关系(QSPR)是什么?

定量活性关系&#xff08;QSAR&#xff09;是什么&#xff1f; 定量活性关系&#xff08;QSAR&#xff0c;Quantitative Structure-Activity Relationship&#xff09;分析是指利用理论计算和统计分析工具来研究系列化合物结构&#xff08;包括二维分子结构、三维分子结构和电…

C++ 学习系列 -- std::list

一 std::list 介绍 list 是 c 中的序列式容器&#xff0c;其实现是双向链表&#xff0c;每个元素都有两个指针&#xff0c;分别指向前一个节点与后一个节点 链表与数组都是计算机常用的内存数据结构&#xff0c;与数组连续内存空间不一样的地方在于&#xff0c;链表的空间是不…

合并不同年度收入数据-外连接

案例需求&#xff1a;统计2019年和2020年的客户销售收入并求和 思路&#xff1a;使用pandas读取excel数据横向连接&#xff0c;使用sum()含函数求和 代码如下&#xff1a; 1、使用pandas读取excel数据 2、由于两个表一个是"客户名称"&#xff0c;一个是客户描述,使…

基于ChatGPT快速入门体验NLP词云

基于ChatGPT快速入门体验NLP词云 一、什么是自然语言处理二、自然语言处理和词云的关系三、Python环境准备四、基于ChatGpt制作词云4.1 ChatGPT生成初级词云代码4.2 ChatGPT生成进阶词云代码4.3 基于ChatGPT解决代码问题4.4 基于ChatGPT建议修改问题代码 一、什么是自然语言处理…

最强中间件!Kafka快速入门(Kafka理论+SpringBoot集成Kafka实践)

自媒体文章上下架 需求分析 媒体端下架文章同时app端也下架文章的实现可以通过feign去调用&#xff0c;但这种实现耦合度太高&#xff0c;这里使用MQ进行解耦 自媒体端一旦上下架文章就发送消息给MQ&#xff0c;文章微服务在去读取消息根据消息内容上下架文章 MQ还可以流量削…

windows server 2012 服务器打开系统远程功能

服务器上开启远程功能 进入服务器&#xff0c;选择“添加角色和功能” 需要选择安装的服务器类型&#xff0c;如图所示 然后在服务器池中选择你需要使用的服务器。 选择完成后&#xff0c;在图示列表下勾选“远程桌面服务” 再选择需要安装的功能和角色服务。 选择完成确认内容…