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 天的股票价格 。 设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票): 卖出股票后,你无法在…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
算法250609 高精度
加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...
背包问题双雄:01 背包与完全背包详解(Java 实现)
一、背包问题概述 背包问题是动态规划领域的经典问题,其核心在于如何在有限容量的背包中选择物品,使得总价值最大化。根据物品选择规则的不同,主要分为两类: 01 背包:每件物品最多选 1 次(选或不选&#…...
精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑
精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑 在电子商务领域,转化率与网站性能是决定商业成败的核心指标。今天,我们将深入解析不同类型电商平台的转化率基准,探讨页面加载速度对用户行为的…...
Docker、Wsl 打包迁移环境
电脑需要开启wsl2 可以使用wsl -v 查看当前的版本 wsl -v WSL 版本: 2.2.4.0 内核版本: 5.15.153.1-2 WSLg 版本: 1.0.61 MSRDC 版本: 1.2.5326 Direct3D 版本: 1.611.1-81528511 DXCore 版本: 10.0.2609…...
