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 中对数据处理主要有两种方式:1)直接对包含数据的的数据项 item 进行操作,这种方法简单、易操作,现实方式单一的缺点,特别是对于大数据或在不同位置重复出现的数据必须依次对其进行操作,如果现实方式改…...
c与c++中的字符串
在c中,string本质上是一个类; string与char *有些区别: char*是一个指针;string是一个类,类内封装了char*,管理这一个字符串,是一个char*的容器 在使用string类型时,要加上其头文…...
Android 获取IP地址的Ping值 NetworkPingUtils
项目里需要对动态配置的Ip列表都去ping下延迟,取出其中最小的三个进行随机取值然后去连接,倒腾了一下午终于搞出来了! 需求实现思路: 1.找到方法去ping IP地址; 2.同时去Ping,不能让用户等待;…...
数据集笔记:OpenCelliD(手机基站开放数据库)
下载数据的方式可见:【数据获取】全球最大手机基站开源数据库 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电脑多开器是一种非常实用的软件工具,它可以让我们在同一个电脑上同时运行多个不同的应用程序,从而提高我们的工作和学习效率。以下是我在使用Windows电脑多开器时的一些心得分享: 确保你的电脑配置足够强大 多开软件需要消耗大量的…...
Android Studio实现简易计算器(带横竖屏,深色浅色模式,更该按钮颜色,selector,style的使用)
目录 前言 运行结果: 运行截屏(p50e) apk文件 源码文件 项目结构 总览 MainActivity.java drawable 更改图标的方法: 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宿主机防火墙添加规则,(或者直接关闭公共网络防火墙,不安全…...
计算机网络(六):应用层
参考引用 计算机网络微课堂-湖科大教书匠计算机网络(第7版)-谢希仁 1. 应用层概述 应用层是计算机网络体系结构的最顶层,是设计和建立计算机网络的最终目的,也是计算机网络中发展最快的部分 早期基于文本的应用 (电子邮件、远程登…...
Sublime Text 4 for Mac激活下载
Sublime Text for Mac是一款适用于Mac平台的文本编辑器。它具有快速的性能和丰富的功能,可以帮助用户快速进行代码编写和文本编辑。 软件下载:Sublime Text 4 for Mac激活下载 该软件具有直观的界面和强大的功能,包括多行选择、代码折叠、自动…...
存在负权边的单源最短路径的原理和C++实现
负权图 此图用朴素迪氏或堆优化迪氏都会出错,floyd可以处理。 负环图 但floyd无法处理负权环,最短距离是无穷小。在环上不断循环。 经过k条边的最短距离(可能有负权变) 贝尔曼福特算法(bellman_ford)就是解决此问题的。 原理 …...
15-自动化测试——理论知识
目录 1.什么是自动化测试? 2.常见的自动化测试分类 2.1.单元测试(Java、Python) 2.2.接口测试(Java、Python) 2.3.UI测试(移动端、网站) 3.如何实施自动化测试? 4.自动化测试…...
学信息系统项目管理师第4版系列17_干系人管理
1. 项目经理和团队管理干系人的能力决定着项目的成败 2. 干系人满意度应作为项目目标加以识别和管理 3. 发展趋势和新兴实践 3.1. 识别所有干系人,而非在限定范围内 3.2. 确保所有团队成员都涉及引导干系人参与的活 3.3. 定期审查干系人群体,可与单…...
专业PDF编辑阅读工具PDF Expert mac中文特点介绍
PDF Expert mac是一款专业的PDF编辑和阅读工具。它可以帮助用户在Mac、iPad和iPhone等设备上查看、注释、编辑、填写和签署PDF文档。 PDF Expert mac软件特点 PDF编辑:PDF Expert提供了丰富的PDF编辑功能,包括添加、删除、移动、旋转、缩放、裁剪等操作…...
处理机调度的概念,层次联系以及七状态模型
1.基本概念 当有一堆任务要处理,但由于资源有限,这些事情没法同时处理。 这就需要确定某种规则来决定处理这些任务的顺序,这就是“调度”研究的问题。 2. 三个层次 1.高级调度(作业调度) 高级调度(作业…...
PS 图层剪贴蒙版使用方法
好 我们先打开PS软件 后面我们需要接触图框工具 在学习图框工具之前 先要掌握剪贴蒙版 这里 我们先点击左上角文件 然后选择新建 我们先新建一个画布出来 然后 我们点击 箭头指向处 新建一个空白图层 点击之后 会就多出一个空白图层 我们在这里 找到 矩形选框工具 然后 …...
总结1008
今日有些小摆烂,在家学习的日子,确实感觉不如在学校好,无论是在时间上,还是在效率上。在家复习效果因人而异吧,都到这个关键阶段了,可不能掉链子啊,明天势必要拿出100%的状态,心静不…...
软件工程从理论到实践客观题汇总(头歌第九章至第十七章)
九、软件体系结构设计 1、软件体系结构设计概述 2、软件体系结构模型的表示方法 3、软件体系结构设计过程 4、设计初步的软件体系结构 5、重用已有软件资源 6、精化软件体系结构 7、设计软件部署模型 8、文档化和评审软件体系结构设计 十、软件用户界面设计 1、用户界面设计概…...
ubuntu与win之间共享文件夹
ubuntu上设置共享文件夹 第一步:点击【设置】或【虚拟机弹窗下面的【设置】选项】 第二步:进入【虚拟机设置】页面,点击【选项】如下图所示 第三步:启用共享文件:点击【总是启用】第四步:添加共享文件&…...
flink处理函数--副输出功能
背景 在flink中,如果你想要访问记录的处理时间或者事件时间,注册定时器,或者是将记录输出到多个输出流中,你都需要处理函数的帮助,本文就来通过一个例子来讲解下副输出 副输出 本文还是基于streaming-with-flink这本…...
Java数据结构————队列
一 、队列 在Java中,Queue是个接口,底层是通过链表实现的。 只允许在一端进行插入数据操作, 在另一端进行删除数据操作的特殊线性表, 队列具有先进先出FIFO(First In First Out) 。 入队列: 进行插入操作的一端称为…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
