Qt model/view 理解 2
这是我对 Qt 的 model/view 内容理解的第二篇 blog,在第一篇文章中,介绍 QTableView 和 QAbstractTableModel,实现显示了对数据源的显示,但是显示的格式和修改的模式都是按照 View 控件的自显示方式。在此,使用 Qt 自带的 QStyledItemDelegate 类实现对特定行 / 列的显示 / 修改模式实现,实现过程中不出现对 item 的代码生成,对 item 的生成由程序自动完成。
在此同样以《c++ gui programming with Qt4》中的 trackEditor 例子作一讲解。
在此,我们首先应当考虑以下几个问题:
1)有一个代理类加到 View 中,处理特定的 View 内容。
2)代理类要完成以下几项工作:a)当用户修改数据时生成用户要求的控件(用户每次修改数据时在相应的位置都会生成控件,所以当控件用完后,应 del 释放资源)。b)设置在生成的修改控件中显示的内容。c)设置要写到 model 中的数据内容。d)设置当结束修改数据后,View 显示的内容。
在此我们需要实现以下 4 个类。
/**
@brief 保存显示数据的类。
*/
class Track/**
@brief 继承的委托类。
*/
class TrackDelegate : public QStyledItemDelegate/**
@brief 继承的模型类。
*/
class TrackModel : public QAbstractTableModel/**
@brief 用于组装显示的控件类。
*/
class TrackEditor : public QDialog
在此,Track TrackModel TrackEditor 的功能在 Qt model/view 理解 1 中做过介绍,在此只列出 code,不再过多介绍。在此主要介绍 TrackDelegate。
Track h 文件
#ifndef TRACK_H
#define TRACK_H#include <QString>/**@projectName ItemView@author qiaowei@date 2018-12-22@version 1.0@description 保存的音频数据,包括音频名称和时长
**/
class Track
{
public:explicit Track(const QString& title = "", int duration = 0);QString getTitle() const;void setTitle(const QString& title);int getDuration() const;void setDuration(int duration);private:/**@author qioawei@date 2018-12-22@description 音频名称**/QString title_;/**@author qioawei@date 2018-12-22@description 音频时长(单位:秒)**/int duration_;
};#endif // TRACK_H
Track.cpp
#include "track.h"Track::Track(const QString &title, int duration) :title_(title),duration_(duration)
{}QString Track::getTitle() const
{return title_;
}void Track::setTitle(const QString &title)
{title_ = title;
}int Track::getDuration() const
{return duration_;
}void Track::setDuration(int duration)
{duration_ = duration;
}
TrackModel.h
#ifndef TRACKMODEL_H#define TRACKMODEL_H#include <QWidget>
#include <QAbstractTableModel>
#include <QList>
#include "track.h"
#include <QObject>/**@brief 继承的模型类。
*/
class TrackModel : public QAbstractTableModel
{Q_OBJECTpublic:explicit TrackModel(QList<Track>* tracks, QObject* parent = 0);~TrackModel();virtual int rowCount(const QModelIndex &parent) const;virtual int columnCount(const QModelIndex &parent) const;virtual QVariant data(const QModelIndex &index, int role) const;virtual bool setData(const QModelIndex &index,const QVariant &value,int role);virtual Qt::ItemFlags flags(const QModelIndex &index) const;private:QList<Track>* tracks;
};#endif // TRACKMODEL_H
TrackEditor h 文件
#ifndef TRACKEDITOR_H#define TRACKEDITOR_H#include <QDialog>#include "track.h"QT_BEGIN_NAMESPACE
class QTableView;
class TrackModel;
class QAbstractTableModel;
QT_END_NAMESPACEnamespace Ui {
class TrackEditor;
}/**@brief 用于组装显示的控件类。
*/
class TrackEditor : public QDialog
{Q_OBJECTpublic:explicit TrackEditor(QList<Track>* tracks, QWidget *parent = 0);~TrackEditor();private:Ui::TrackEditor *ui;QTableView* tableView;TrackModel* model;//QAbstractTableModel* model;
};#endif // TRACKEDITOR_H
TrackDelegate h 文件
#ifndef TRACKDELEGATE_H#define TRACKDELEGATE_H#include <QObject>
#include <QStyledItemDelegate>QT_BEGIN_NAMESPACE
class QPainter;
QT_END_NAMESPACE/**@brief 继承的委托类。
*/
class TrackDelegate : public QStyledItemDelegate
{
public:explicit TrackDelegate(QObject* parent = 0);~TrackDelegate();virtual QWidget* createEditor(QWidget *parent,const QStyleOptionViewItem &option,const QModelIndex &index) const;virtual void setEditorData(QWidget* parent,const QModelIndex& index) const;virtual void setModelData(QWidget* editor,QAbstractItemModel* model,const QModelIndex& index) const;virtual void updateEditorGeometry(QWidget* editor,const QStyleOptionViewItem& option,const QModelIndex& index) const;virtual void paint(QPainter* painter,const QStyleOptionViewItem &option,const QModelIndex &index) const;virtual QSize sizeHint(const QStyleOptionViewItem &option,const QModelIndex &index) const;private:bool isRightColumn(const QModelIndex& index, const int column) const;
private slots:void commitAndCloseEditor();private:static const int columnNumber;
};#endif // TRACKDELEGATE_H
TrackDelegate cpp 文件
#include "trackdelegate.h"
#include <QTimeEdit>
#include <QPainter>
#include <QApplication>#include "trackmodel.h"const int TrackDelegate::columnNumber = 1;TrackDelegate::TrackDelegate(QObject* parent) :QStyledItemDelegate(parent)
{}TrackDelegate::~TrackDelegate()
{}QWidget* TrackDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &option,const QModelIndex &index) const
{if (isRightColumn(index, TrackDelegate::columnNumber)) {QTimeEdit *timeEdit = new QTimeEdit(parent);timeEdit->setDisplayFormat("hh:mm");//当控件结束编辑内容时,触发释放资源connect(timeEdit, &QTimeEdit::editingFinished,this, &TrackDelegate::commitAndCloseEditor);//int secs = index.model()->data(index, Qt::DisplayRole).toInt();int secs = index.model()->data(index, Qt::EditRole).toInt();QTime time(secs / 60, secs % 60);timeEdit->setTime(time);return timeEdit;} else {return QStyledItemDelegate::createEditor(parent,option,index);}
}void TrackDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{if ( !index.isValid()) {return;}QTimeEdit* timeEditor = qobject_cast<QTimeEdit*>(editor);if ( !timeEditor) {return;}if (isRightColumn(index, TrackDelegate::columnNumber)) {int secs = index.model()->data(index, Qt::EditRole).toInt();QTime time(secs / 60, secs % 60);timeEditor->setTime(time);} else {QStyledItemDelegate::setEditorData(editor, index);}
}void TrackDelegate::setModelData(QWidget *editor,QAbstractItemModel *model,const QModelIndex &index) const
{if ( !index.isValid()) {return;}QTimeEdit* timeEditor = qobject_cast<QTimeEdit*>(editor);if ( !timeEditor) {return;}if (isRightColumn(index, TrackDelegate::columnNumber)) {QTime time = timeEditor->time();int secs = time.hour() * 60 + time.minute();model->setData(index, secs, Qt::EditRole);} else {QStyledItemDelegate::setModelData(editor,model,index);}
}void TrackDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option,const QModelIndex &index) const
{Q_UNUSED(index);editor->setGeometry(option.rect);
}void TrackDelegate::paint(QPainter *painter,const QStyleOptionViewItem &option,const QModelIndex &index) const
{if (isRightColumn(index, TrackDelegate::columnNumber)) {int secs = index.model()->data(index, Qt::EditRole).toInt();QString text = QString("%1:%2").arg(secs / 60, 2, 10, QChar('0')).arg(secs % 60, 2, 10, QChar('0'));//获取项风格设置QStyleOptionViewItem myOption = option;myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;painter->drawText(option.rect, text);} else {QStyledItemDelegate::paint(painter, option, index);}
}QSize TrackDelegate::sizeHint(const QStyleOptionViewItem &option,const QModelIndex &index) const
{return option.rect.size();
}void TrackDelegate::commitAndCloseEditor()
{QTimeEdit* editor = qobject_cast<QTimeEdit*>(sender());emit commitData(editor);emit closeEditor(editor);
}bool TrackDelegate::isRightColumn(const QModelIndex &index,const int column) const
{if ( !index.isValid()) {return false;}if (index.column() == column) {return true;} else {return false;}
}
createEditor 用于创建用户自己需要的显示数据控件。
setEditorData 用于设置显示控件中显示的具体数据信息。
setModelData 用户设置模型的数据,也可理解为当显示的数据发生变化后,用户 update 模型数据,保持显示 / 储存内容一致。
paint 由用户自己绘制要显示的内容信息(很重要,当你点击时间框修改时间,要改的内容为原显示内容并允许你修改,而不是数据变为 00:00,让你修改)。
commitAndCloseEditor 创建关于 commitData 和 closeEditor 的信号槽链接,保证当代理控件的数据修改完成后,释放信号,保存数据(保存数据步骤由系统自动完成)。
在此要求注意内容:
在 TrackModel 类中的 setData 方法应当注意,data 的值应从 value 得出而不是通过 model 的 data 得出,model 得出的数据是原来保存的,而不是用户修改的。
相关文章:
Qt model/view 理解 2
这是我对 Qt 的 model/view 内容理解的第二篇 blog,在第一篇文章中,介绍 QTableView 和 QAbstractTableModel,实现显示了对数据源的显示,但是显示的格式和修改的模式都是按照 View 控件的自显示方式。在此,使用 Qt 自带…...

【LeetCode热题100】--114.二叉树展开为链表
114.二叉树展开为链表 方法一:对二叉树进行先序遍历,得到各个节点被访问到的顺序,利用数组存储下来,然后在先序遍历之后更新每个节点的左右节点的信息,将二叉树展开为链表 /*** Definition for a binary tree node.* …...

Java | Maven(知识点查询)
文章目录 Maven知识速查1. Maven概述2. Maven的作用3. Maven的下载4. Maven的环境配置5. Maven 的基础组成5.1 Maven仓库5.1.1 本地仓库配置:5.1.2 中央仓库配置:5.1.3 镜像仓库配置 5.2 Maven坐标 6. Maven项目6.1 手工创建Maven项目6.2 自动构建项目 7…...

Vmware 静态网络配置
概述 仅主机模式(VMware1):使用host-only的方式是不能和外界通信的,只能够和本机的物理网卡通信 桥接(VMnet0):使用桥接的方式使得自己的虚拟机和自己的真实机网卡在同一个网段 NAT࿰…...

【数据结构--八大排序】之希尔排序
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
Linux中生成so库的文件引用另一个so库问题的解决
文章目录 一、问题介绍二、问题解决 一、问题介绍 由于项目需求,需要将一个“编译时引用了另一个动态链接库”的文件(名为main.c),再编译成一个动态链接库。 简要说明一下,即原本的项目代码里,包含main.c…...
EDI是连接原始电子商务和现代电子商务的纽带
EDI是连接原始电子商务和现代电子商务的纽带。 EDI(Electronic Data Interchange,电子数据交换)是一种电子通信技术,用于在不同组织之间以结构化和标准化的方式交换业务文档和数据。EDI使企业能够更有效地与供应商、客户和合作伙…...

星宿UI2.4资源付费变现小程序源码 支持流量主
第一个小程序为星宿小程序 目前是最新版2.0 搭建星宿需要:备用域名 服务器 微信小程序账号 功能:文章展示 文章分类 资源链接下载 轮播图 直接下载附件功能 很多 很适合做资源类分享 源码下载:https://download.csdn.net/download/m0_6604…...
代码随想录训练营二刷第四十六天 | 完全背包 518. 零钱兑换 II 377. 组合总和 Ⅳ
代码随想录训练营二刷第四十六天 | 518. 零钱兑换 II 377. 组合总和 Ⅳ 一、518. 零钱兑换 II 题目链接:https://leetcode.cn/problems/coin-change-ii/ 思路:完全背包求组合数,递推公式dp[j]dp[j-nums[i]]。 求组合数,物品在外…...

python安装第三方模块方法
正常情况下安装python第三方模块没啥说的,但是由于python安装模块默认是在外网下载安装,牵扯外网网速问题,所以可以配置下使用国内某镜像源来下载模块 python -m pip install xxxxxxxxxxx 和 pip install xxxxxxxxxx 的命令都可下载安装第三…...
广西小贷公司设立及小贷牌照申请政策要求
关于广西小额贷款公司设立及小贷牌照申请,依据《关于小额贷款公司试点的指导意见》(银监发〔2008〕23号);《广西壮族自治区小额贷款公司管理办法》(桂政发〔2009〕71号);《广西壮族自治区人民政…...
PyTorch应用实战二:实现卷积神经网络进行图像分类
文章目录 实验环境MNIST数据集1.网络结构2.程序实现2.1 导入相关库2.2 构建卷积神经网络模型2.3 加载MNIST数据集2.4 训练模型 附:系列文章 实验环境 python3.6 pytorch1.8.0 import torch print(torch.__version__)1.8.0MNIST数据集 MNIST数字数据集是一组手写…...
面试系列 - Java常见算法(二)
目录 一、排序算法 1、插入排序(Insertion Sort) 2、归并排序(Merge Sort) 二、图形算法 1、最短路径算法(Dijkstra算法、Floyd-Warshall算法) Dijkstra算法 Floyd-Warshall算法 2、最小生成树算法&…...

Cortex-A9 架构
一、Cortex-A 处理器运行模式 Cortex-A9处理器有 9中处理模式,如下表所示: 九种运行模式 在上表中,除了User(USR)用户模式以外,其它8种运行模式都是特权模式,在特权模式下,程序可以访问所有的系统资源。这…...

【C语言】循环结构程序设计(第二部分 -- 习题讲解)
前言:昨天我们学习了C语言中循环结构程序设计,并分析了循环结构的特点和实现方法,有了初步编写循环程序的能力,那么今天我们通过一些例子来进一步掌握循环程序的编写和应用。 💖 博主CSDN主页:卫卫卫的个人主页 💞 &am…...

UGUI交互组件Toggle
一.Toggle对象的构造 Toggle和Button类似,是交互组件的一种 如果所示,通过菜单创建了两个Toggle,Toggle2中更换了背景和标记资源 对象说明Toggle含有Toggle组件的对象Background开关背景Checkmark开关选中标记Label名称文本 二.Toggle组件属…...

亲,您的假期余额已经严重不足了......
引言 大家好,我是亿元程序员,一位有着8年游戏行业经验的主程。 转眼八天长假已经接近尾声了,今天来总结一下大家的假期,聊一聊假期关于学习的看法,并预估一下大家节后大家上班时的样子。 1.放假前一天 即将迎来八天…...

【软件测试】自动化测试selenium(一)
文章目录 一. 什么是自动化测试二. Selenium的介绍1. Selenium是什么2. Selenium的特点3. Selenium的工作原理4. SeleniumJava的环境搭建 一. 什么是自动化测试 自动化测试是指使用软件工具或脚本来执行测试任务的过程,以替代人工进行重复性、繁琐或耗时的测试活动…...

Nginx实现动静分离
一、概述 1、什么是动静分离 动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路。 动静分离简单的概…...
【算法题】309. 买卖股票的最佳时机含冷冻期
题目: 给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。 设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票): 卖出股票后,你无法在…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...

R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...

Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...

rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...

JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...