「Qt Widget中文示例指南」如何实现一个快捷编辑器(二)

Qt 是目前最先进、最完整的跨平台C++开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。

快捷编辑器示例展示了如何创建一个基本的读写层次模型,来与Qt的标准视图和QKeySequenceEdit类一起使用。

点击获取Qt Widget组件下载(Q技术交流:166830288)

「Qt Widget中文示例指南」如何实现一个快捷编辑器

Qt的模型/视图架构为视图提供了一种标准的方式来操作数据源中的信息,使用数据的抽象模型来简化和标准化访问数据的方式。快捷编辑器模型将操作表示为项目树,并允许视图通过基于索引的系统访问此数据。更一般地说,可以使用模型以树结构的形式表示数据,方法是允许每个项作为子项表的父项。

在上文中(点击这里回顾>>),我们为大家介绍了快捷编辑器的设计理念及结构等,本文将继续介绍一些具体的实现类。

ShortcutEditorModel类实现

构造函数接受一个参数,其中包含模型将与视图和委托共享的数据:

ShortcutEditorModel::ShortcutEditorModel(QObject *parent)
: QAbstractItemModel(parent)
{
m_rootItem = new ShortcutEditorModelItem({tr("Name"), tr("Shortcut")});
}

由构造函数来为模型创建根项,为方便起见,此项仅包含垂直标题数据。我们还使用它来引用包含模型数据的内部数据结构,并使用它来表示模型中顶级项的假想父项。

模型的内部数据结构由setupModelData()函数填充,我们将在本文末尾单独研究这个函数。

析构函数确保在模型被销毁时删除根项及其所有子类:

ShortcutEditorModel::~ShortcutEditorModel()
{
delete m_rootItem;
}

由于在构造和设置模型之后我们不能向模型中添加数据,因此这简化了管理内部项目树的方式。

模型必须实现index()函数来为视图和委托提供索引,以便在访问数据时使用。当其他组件被它们的行号、列号以及它们的父模型索引引用时,为它们创建索引。如果将无效的模型索引指定为父索引,则由模型返回与模型中的顶级项对应的索引。

当提供模型索引时,我们首先检查它是否有效。如果不是假定引用的是顶级项;否则我们使用模型索引的internalPointer()  函数从模型索引中获取数据指针,并使用它来引用TreeItem对象。注意我们构造的所有模型索引都将包含一个指向现有TreeItem的指针,因此可以保证接收到的任何有效模型索引都将包含一个有效的数据指针。

void ShortcutEditorModel::setActions()
{
beginResetModel();
setupModelData(m_rootItem);
endResetModel();
}

由于此函数的行和列参数引用相应父项的子项,因此我们使用TreeItem::child()函数获得该项,createIndex()函数用于创建要返回的模型索引。我们指定行号和列号,以及指向项本身的指针,稍后可以使用模型索引来获取项目的数据。

TreeItem对象的定义方式使得parent()函数的编写变得简单:

QModelIndex ShortcutEditorModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();

ShortcutEditorModelItem *parentItem;
if (!parent.isValid())
parentItem = m_rootItem;
else
parentItem = static_cast<ShortcutEditorModelItem*>(parent.internalPointer());

ShortcutEditorModelItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);

return QModelIndex();
}

我们只需要确保永远不会返回与根项对应的模型索引,为了与index()函数的实现方式保持一致,我们为模型中任何顶级项的父项返回一个无效的模型索引。

当创建要返回的模型索引时,我们必须在父项中指定父项的行号和列号。我们可以很容易地使用TreeItem::row()函数发现行号,但是我们遵循指定0作为父列号的约定。模型索引是用createIndex()创建的,方法与index()函数相同。

rowCount()函数只是返回对应于给定模型索引的TreeItem的子条目的数量,或者如果指定了无效索引则返回顶级条目的数量:

QModelIndex ShortcutEditorModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();

ShortcutEditorModelItem *childItem = static_cast<ShortcutEditorModelItem*>(index.internalPointer());
ShortcutEditorModelItem *parentItem = childItem->parentItem();

if (parentItem == m_rootItem)
return QModelIndex();

return createIndex(parentItem->row(), 0, parentItem);
}

由于每个项目都管理自己的列数据,因此columnCount()函数必须调用项目自己的columnCount()函数来确定给定模型索引有多少列。与rowCount()函数一样,如果指定了无效的模型索引,则返回的列数将从根项确定:

int ShortcutEditorModel::rowCount(const QModelIndex &parent) const
{
ShortcutEditorModelItem *parentItem;
if (parent.column() > 0)
return 0;

if (!parent.isValid())
parentItem = m_rootItem;
else
parentItem = static_cast<ShortcutEditorModelItem*>(parent.internalPointer());

return parentItem->childCount();
}

数据通过Data()从模型中获得,由于项目管理它自己的列,我们需要使用列号来使用TreeItem::data()函数检索数据:

int ShortcutEditorModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return static_cast<ShortcutEditorModelItem*>(parent.internalPointer())->columnCount();

return m_rootItem->columnCount();
}

注意,在这个实现中我们只支持DisplayRole,并且还为无效的模型索引返回无效的QVariant对象。

我们使用flags()函数来确保视图知道模型是只读的:

QVariant ShortcutEditorModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();

ShortcutEditorModelItem *item = static_cast<ShortcutEditorModelItem*>(index.internalPointer());
return item->data(index.column());
}

headerData()函数返回我们方便地存储在根项中的数据:

Qt::ItemFlags ShortcutEditorModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;

Qt::ItemFlags modelFlags = QAbstractItemModel::flags(index);
if (index.column() == static_cast<int>(Column::Shortcut))
modelFlags |= Qt::ItemIsEditable;

return modelFlags;
}

这些信息可以以不同的方式提供:在构造函数中指定,或者硬编码到headerData()函数中。

QVariant ShortcutEditorModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
return m_rootItem->data(section);
}

return QVariant();
}

TODO

void ShortcutEditorModel::setupModelData(ShortcutEditorModelItem *parent)
{
ActionsMap actionsMap;
Application *application = static_cast<Application *>(QCoreApplication::instance());
ActionManager *actionManager = application->actionManager();
const QList<QAction *> registeredActions = actionManager->registeredActions();
for (QAction *action : registeredActions) {
QString context = actionManager->contextForAction(action);
QString category = actionManager->categoryForAction(action);
actionsMap[context][category].append(action);
}

QAction *nullAction = nullptr;
const QString contextIdPrefix = "root";
// Go through each context, one context - many categories each iteration
for (const auto &contextLevel : actionsMap.keys()) {
ShortcutEditorModelItem *contextLevelItem = new ShortcutEditorModelItem({contextLevel, QVariant::fromValue(nullAction)}, parent);
parent->appendChild(contextLevelItem);

// Go through each category, one category - many actions each iteration
for (const auto &categoryLevel : actionsMap[contextLevel].keys()) {
ShortcutEditorModelItem *categoryLevelItem = new ShortcutEditorModelItem({categoryLevel, QVariant::fromValue(nullAction)}, contextLevelItem);
contextLevelItem->appendChild(categoryLevelItem);
for (QAction *action : actionsMap[contextLevel][categoryLevel]) {
QString name = action->text();
if (name.isEmpty() || !action)
continue;

ShortcutEditorModelItem *actionLevelItem = new ShortcutEditorModelItem({name, QVariant::fromValue(reinterpret_cast<void *>(action))}, categoryLevelItem);
categoryLevelItem->appendChild(actionLevelItem);
}
}
}
}

TODO

bool ShortcutEditorModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role == Qt::EditRole && index.column() == static_cast<int>(Column::Shortcut)) {
QString keySequenceString = value.toString();
ShortcutEditorModelItem *item = static_cast<ShortcutEditorModelItem *>(index.internalPointer());
QAction *itemAction = item->action();
if (itemAction) {
if (keySequenceString == itemAction->shortcut().toString(QKeySequence::NativeText))
return true;
itemAction->setShortcut(keySequenceString);
}
Q_EMIT dataChanged(index, index);

if (keySequenceString.isEmpty())
return true;
}

return QAbstractItemModel::setData(index, value, role);
}

TODO

在模型中设置数据

我们使用setupModelData()函数在模型中设置初始数据,该函数检索已注册的操作文本并创建记录数据和整体模型结构的项目对象。当然,这个函数的工作方式是非常特定于这个模型的。

为了确保模型正确工作,只需要创建具有正确数据和父项的ShortcutEditorModelItem实例。

Qt Widget组件推荐
  • QtitanRibbon - Ribbon UI组件:是一款遵循Microsoft Ribbon UI Paradigm for Qt技术的Ribbon UI组件,QtitanRibbon致力于为Windows、Linux和Mac OS X提供功能完整的Ribbon组件。
  • QtitanChart - Qt类图表组件:是一个C ++库,代表一组控件,这些控件使您可以快速地为应用程序提供漂亮而丰富的图表。
  • QtitanDataGrid - Qt网格组件:提供了一套完整的标准 QTableView 函数和传统组件无法实现的独特功能。使您能够将不同来源的各类数据加载到一个快速、灵活且功能强大的可编辑网格中,支持排序、分组、报告、创建带状列、拖放按钮和许多其他方便的功能。
  • QtitanDocking:允许您像 Visual Studio 一样为您的伟大应用程序配备可停靠面板和可停靠工具栏。黑色、白色、蓝色调色板完全支持 Visual Studio 2019 主题!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

1U机架式多卡聚合设备在视频指挥车上的应用解决方案

随着信息技术的飞速发展&#xff0c;视频指挥车作为现代化指挥系统的重要组成部分&#xff0c;在各类应急指挥调度中发挥着越来越重要的作用。而1U机架式多卡聚合设备&#xff0c;以其高带宽、高可用性和高稳定性的特点&#xff0c;成为视频指挥车中不可或缺的关键设备。本文将…

Softing工业新版dataFEED OPC Suite支持访问SINUMERIK 840D数控机床

2024年4月17日&#xff08;哈尔&#xff09;&#xff0c;Softing工业自动化宣布发布dataFEED OPC Suite V5.35新版。该版本支持访问SINUMERIK 840D数控机床数据&#xff0c;并集成了Web服务功能。 &#xff08;dataFEED OPC Suite V5.35支持访问SINUMERIK 840D数控机床&#xf…

腾讯云服务器部署前后端服务

服务器&#xff1a;OpenCloudOS &#xff08;兼容centos8&#xff09; 后端&#xff1a;javaSpringboot 前端&#xff1a;Vue 下载jdk 1&#xff09;下载jdk11 wget https://download.java.net/openjdk/jdk11/ri/openjdk-1128_linux-x64_bin.tar.gz 2&#xff09;解压jdk …

基于微信小程序+JAVA Springboot 实现的【停车场小程序】app+后台管理系统 (内附设计LW + PPT+ 源码+ 演示视频 下载)

项目名称 项目名称&#xff1a; 停车场微信小程序的设计与实现 在当前信息技术飞速发展的背景下&#xff0c;停车场微信小程序的开发成为了一个创新的解决方案&#xff0c;旨在提高停车场管理的效率和用户的停车体验。本项目通过深入分析现有停车场管理系统的不足&#xff0c…

硬件FMEA与软件FMEA的区别——FMEA软件

​免费试用FMEA软件-免费版-SunFMEA 在产品开发和制造过程中&#xff0c;失效模式与影响分析&#xff08;FMEA&#xff09;作为一种预防性的质量工具&#xff0c;对于确保产品性能和质量至关重要。然而&#xff0c;硬件FMEA和软件FMEA在应用和实践方面存在显著的区别。本文旨在…

第51期|GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

双星号(**)和单星号(*)在Python参数传递中的妙用

在Python中&#xff0c;参数传递是一个非常重要的概念&#xff0c;它允许函数接收任意数量的参数。而双星号(**)和单星号(*)在参数传递中扮演着关键角色。本文将详细讲解这两个符号的用法&#xff0c;并通过示例代码帮助初学者理解它们的工作原理。 单星号(*) 单星号(*)用于函…

华为配置带反射器的iNOF功能实验

配置带反射器的iNOF功能示例 适用产品和版本 安装了SAN系列单板的CE16800系列交换机V300R020C10或更高版本。 安装了P系列单板的CE16800系列交换机V300R021C00或更高版本。 CE6866、CE6866K、CE8851-32CQ8DQ-P、CE8851K系列交换机V300R020C00或更高版本。 CE6860-SAN、CE8850-S…

MyBatis——动态 SQL

一、if 标签 <mapper namespace"com.powernode.mybatis.mapper.CarMapper"><select id"selectByMultiCondition" resultType"car">select * from t_car where<if test"brand ! null and brand ! ">brand like #{br…

【Docker】docker 镜像如何push到私有docker仓库

文章目录 一、 网址解析对于Linux和macOS系统&#xff1a;对于Windows系统&#xff1a; 二、 镜像push 一、 网址解析 希望 registry.meizu.com 能够解析到内网IP地址&#xff08;例如10.128.17.157&#xff09;&#xff0c;您可以通过修改主机的 hosts 文件来实现。 hosts 文…

百度文心一言 java 支持流式输出,Springboot+ sse的demo

参考&#xff1a;GitHub - mmciel/wenxin-api-java: 百度文心一言Java库&#xff0c;支持问答和对话&#xff0c;支持流式输出和同步输出。提供SpringBoot调用样例。提供拓展能力。 1、依赖 <dependency> <groupId>com.baidu.aip</groupId> <artifactId…

7天精通Web APIs——正则阶段案例(理论+实战)(第六天)

正则表达式的定义和使用 定义&#xff1a;是一种匹配模式&#xff0c;用于匹配字符串中字符组合 作用&#xff1a;表单验证&#xff08;匹配&#xff09;、过滤敏感词&#xff08;替换&#xff09;、字符串中提取我们想要的部分&#xff08;提取&#xff09; 使用分为两步&…

基于C#开发web网页管理系统模板流程-登录界面

前言&#xff0c;首先介绍一下本项目将要实现的功能 &#xff08;一&#xff09;登录界面 实现一个不算特别美观的登录窗口&#xff0c;当然这一步跟开发者本身的设计美学相关&#xff0c;像蒟蒻博主就没啥艺术细胞&#xff0c;勉强能用能看就行…… &#xff08;二&#xff09…

STK12 RPO模块学习(3)

一、Maintain NMC RPO Sequence Maintain Natural Motion Circumnavigation RPO序列在目标星和追踪星经历不同的力的情况下保持NMC。通常这种差异是由于阻力和太阳光压造成的。这些是主要不同力当执行接近任务的时候&#xff0c;因为重力和相对三体摄动力非常小当相对距离在10…

思源笔记如何结合群晖WebDav实现云同步数据

文章目录 1. 开启群晖WebDav 服务2. 本地局域网IP同步测试3. 群晖安装Cpolar4. 配置远程同步地址5. 笔记远程同步测试6. 固定公网地址7. 配置固定远程同步地址 在数字化时代&#xff0c;信息的同步与共享变得尤为重要。无论是个人用户还是企业团队&#xff0c;都渴望能够实现跨…

架构的设计

文章目录 架构设计2024心得优秀博客mall微服务项目架构mall单体项目架构 架构设计2024 心得 优秀博客 mall优秀开源仓库地址Spring Cloud各种组件的教程 mall微服务项目架构 图片和文档引用地址 https://gitee.com/macrozheng/springcloud-learning 架构设计 前端通过ngin…

计算机网络5——运输层4TCP拥塞控制

文章目录 一、拥塞控制的一般原理二、举例三、理解四、TCP 的拥塞控制方法1、慢开始和拥塞避免 五、主动队列管理AOM1、背景2、介绍3、实现 一、拥塞控制的一般原理 在计算机网络中的链路容量(即带宽)、交换节点中的缓存和处理机等都是网络的资源。在某段时间&#xff0c;若对…

一道dp错题

dis(a,b)就是两点之间的距离公式 那么这道题该怎么解呢,.先看数据范围x,y<1e4,so,18个点两点之间距离最大18*1e4*sqrt(2)<2^18,所以如果跳过的点大于18个点,那么显然一个区间内最多不会跳跃超过17个点 现在我们想知道前i个点跳跃几次在哪跳跃能够达到最小花费,不妨设跳…

Vue的学习 —— <vue响应式基础>

目录 前言 正文 单文件组件 什么是单文件组件 单文件组件使用方法 数据绑定 什么是数据绑定 数据绑定的使用方法 响应式数据绑定 响应式数据绑定的使用方法 ref() 函数 reactive()函数 toRef()函数 toRefs()函数 案例练习 前言 Vue.js 以其高效的数据绑定和视图…

2024统计建模中国新质生产力统计测度与时空演变及其驱动因素研究

高质量成品论文46页word版本1.5w字书写完整数据集1000行py代码一等奖论文&#xff01;这里仅展示部分内容&#xff0c;完整版在下面的链接。 【1.5w字全网最佳】2024统计建模大赛高质量成品论文39页配套完整代码运行全套数据集https://www.jdmm.cc/file/2710661/ 中国新质生产…