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

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&#xff0c;在第一篇文章中&#xff0c;介绍 QTableView 和 QAbstractTableModel&#xff0c;实现显示了对数据源的显示&#xff0c;但是显示的格式和修改的模式都是按照 View 控件的自显示方式。在此&#xff0c;使用 Qt 自带…...

【LeetCode热题100】--114.二叉树展开为链表

114.二叉树展开为链表 方法一&#xff1a;对二叉树进行先序遍历&#xff0c;得到各个节点被访问到的顺序&#xff0c;利用数组存储下来&#xff0c;然后在先序遍历之后更新每个节点的左右节点的信息&#xff0c;将二叉树展开为链表 /*** 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 本地仓库配置&#xff1a;5.1.2 中央仓库配置&#xff1a;5.1.3 镜像仓库配置 5.2 Maven坐标 6. Maven项目6.1 手工创建Maven项目6.2 自动构建项目 7…...

Vmware 静态网络配置

概述 仅主机模式&#xff08;VMware1&#xff09;&#xff1a;使用host-only的方式是不能和外界通信的&#xff0c;只能够和本机的物理网卡通信 桥接&#xff08;VMnet0&#xff09;&#xff1a;使用桥接的方式使得自己的虚拟机和自己的真实机网卡在同一个网段 NAT&#xff0…...

【数据结构--八大排序】之希尔排序

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …...

Linux中生成so库的文件引用另一个so库问题的解决

文章目录 一、问题介绍二、问题解决 一、问题介绍 由于项目需求&#xff0c;需要将一个“编译时引用了另一个动态链接库”的文件&#xff08;名为main.c&#xff09;&#xff0c;再编译成一个动态链接库。 简要说明一下&#xff0c;即原本的项目代码里&#xff0c;包含main.c…...

EDI是连接原始电子商务和现代电子商务的纽带

EDI是连接原始电子商务和现代电子商务的纽带。 EDI&#xff08;Electronic Data Interchange&#xff0c;电子数据交换&#xff09;是一种电子通信技术&#xff0c;用于在不同组织之间以结构化和标准化的方式交换业务文档和数据。EDI使企业能够更有效地与供应商、客户和合作伙…...

星宿UI2.4资源付费变现小程序源码 支持流量主

第一个小程序为星宿小程序 目前是最新版2.0 搭建星宿需要&#xff1a;备用域名 服务器 微信小程序账号 功能&#xff1a;文章展示 文章分类 资源链接下载 轮播图 直接下载附件功能 很多 很适合做资源类分享 源码下载&#xff1a;https://download.csdn.net/download/m0_6604…...

代码随想录训练营二刷第四十六天 | 完全背包 518. 零钱兑换 II 377. 组合总和 Ⅳ

代码随想录训练营二刷第四十六天 | 518. 零钱兑换 II 377. 组合总和 Ⅳ 一、518. 零钱兑换 II 题目链接&#xff1a;https://leetcode.cn/problems/coin-change-ii/ 思路&#xff1a;完全背包求组合数&#xff0c;递推公式dp[j]dp[j-nums[i]]。 求组合数&#xff0c;物品在外…...

python安装第三方模块方法

正常情况下安装python第三方模块没啥说的&#xff0c;但是由于python安装模块默认是在外网下载安装&#xff0c;牵扯外网网速问题&#xff0c;所以可以配置下使用国内某镜像源来下载模块 python -m pip install xxxxxxxxxxx 和 pip install xxxxxxxxxx 的命令都可下载安装第三…...

广西小贷公司设立及小贷牌照申请政策要求

关于广西小额贷款公司设立及小贷牌照申请&#xff0c;依据《关于小额贷款公司试点的指导意见》&#xff08;银监发〔2008〕23号&#xff09;&#xff1b;《广西壮族自治区小额贷款公司管理办法》&#xff08;桂政发〔2009〕71号&#xff09;&#xff1b;《广西壮族自治区人民政…...

PyTorch应用实战二:实现卷积神经网络进行图像分类

文章目录 实验环境MNIST数据集1.网络结构2.程序实现2.1 导入相关库2.2 构建卷积神经网络模型2.3 加载MNIST数据集2.4 训练模型 附&#xff1a;系列文章 实验环境 python3.6 pytorch1.8.0 import torch print(torch.__version__)1.8.0MNIST数据集 MNIST数字数据集是一组手写…...

面试系列 - Java常见算法(二)

目录 一、排序算法 1、插入排序&#xff08;Insertion Sort&#xff09; 2、归并排序&#xff08;Merge Sort&#xff09; 二、图形算法 1、最短路径算法&#xff08;Dijkstra算法、Floyd-Warshall算法&#xff09; Dijkstra算法 Floyd-Warshall算法 2、最小生成树算法&…...

Cortex-A9 架构

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

【C语言】循环结构程序设计(第二部分 -- 习题讲解)

前言:昨天我们学习了C语言中循环结构程序设计&#xff0c;并分析了循环结构的特点和实现方法&#xff0c;有了初步编写循环程序的能力&#xff0c;那么今天我们通过一些例子来进一步掌握循环程序的编写和应用。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &am…...

UGUI交互组件Toggle

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

亲,您的假期余额已经严重不足了......

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

【软件测试】自动化测试selenium(一)

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

Nginx实现动静分离

一、概述 1、什么是动静分离 动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来&#xff0c;动静资源做好了拆分以后&#xff0c;我们就可以根据静态资源的特点将其做缓存操作&#xff0c;这就是网站静态化处理的核心思路。 动静分离简单的概…...

【算法题】309. 买卖股票的最佳时机含冷冻期

题目&#xff1a; 给定一个整数数组prices&#xff0c;其中第 prices[i] 表示第 i 天的股票价格 。 设计一个算法计算出最大利润。在满足以下约束条件下&#xff0c;你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;: 卖出股票后&#xff0c;你无法在…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

短视频矩阵系统文案创作功能开发实践,定制化开发

在短视频行业迅猛发展的当下&#xff0c;企业和个人创作者为了扩大影响力、提升传播效果&#xff0c;纷纷采用短视频矩阵运营策略&#xff0c;同时管理多个平台、多个账号的内容发布。然而&#xff0c;频繁的文案创作需求让运营者疲于应对&#xff0c;如何高效产出高质量文案成…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

android RelativeLayout布局

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

JDK 17 序列化是怎么回事

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