使用图形视图框架(Graphics View Framework)在QML中创建交互式图形界面

使用图形视图框架(Graphics View Framework)在QML中创建交互式图形界面

  • 使用图形视图框架(Graphics View Framework)在QML中创建交互式图形界面
    • 使用图形视图框架(Graphics View Framework)在QML中创建交互式图形界面
    • 什么是图形视图框架(Graphics View Framework)?
    • 在QML中使用图形视图框架
      • 步骤1:项目配置
      • 步骤2:创建QmlGraphicsView类
      • 步骤3:注册自定义类型
      • 步骤4:创建QML界面
      • 步骤5:运行应用程序
      • 完整代码
    • 总结

Graphics View Framework

使用图形视图框架(Graphics View Framework)在QML中创建交互式图形界面

在现代应用程序开发中,图形界面是用户体验的关键。Qt框架为我们提供了一种强大而灵活的方式来创建各种图形界面,而QML(Qt Meta-Object Language)是Qt的一部分,用于设计和构建现代、响应式的用户界面。本文将介绍如何在QML中使用图形视图框架,以创建交互式的图形界面。

什么是图形视图框架(Graphics View Framework)?

图形视图框架是Qt中的一个核心组件,它允许开发者创建和管理2D图形场景。这个框架提供了一个强大的工具集,用于在应用程序中显示和处理图形元素,例如矩形、文本、线条等。它不仅支持静态图形展示,还支持交互和动画效果。

在QML中使用图形视图框架

在QML中使用图形视图框架需要进行一些设置和配置。下面是一些步骤,帮助您在项目中集成图形视图框架:

步骤1:项目配置

首先,确保您的Qt项目已正确配置。在项目的.pro文件中,确保已添加QT += quick widgets,并且设置了正确的Qt版本。还要配置文件的字符集,确保使用UTF-8编码。

步骤2:创建QmlGraphicsView类

在项目中,您需要创建一个自定义的QmlGraphicsView类,该类继承自QQuickPaintedItem,用于在QML中显示图形内容。这个类将充当图形视图的容器。

// QmlGraphicsView.h
#pragma once// Include necessary Qt headersclass QmlGraphicsView : public QQuickPaintedItem
{Q_OBJECTpublic:QmlGraphicsView(QQuickItem* parent = nullptr): QQuickPaintedItem(parent) {// 初始化图形场景并添加图形元素// 设置交互选项}// 实现绘制函数void paint(QPainter* painter) override {// 绘制图形内容}signals:// 自定义信号private slots:// 自定义槽函数protected:// 处理鼠标和交互事件的函数
};
步骤3:注册自定义类型

main.cpp中,使用qmlRegisterType函数将自定义的QmlGraphicsView类注册为QML类型,以便在QML文件中使用。

qmlRegisterType<QmlGraphicsView>("QmlWidgets", 1, 0, "QmlGraphicsView");
步骤4:创建QML界面

在QML文件(例如main.qml)中,导入所需的Qt Quick模块和自定义类型,然后创建界面并将自定义的QmlGraphicsView作为子项嵌套在其中。

import QtQuick 2.15
import QtQuick.Window 2.15
import QmlWidgets 1.0Window {width: 640height: 480visible: truetitle: qsTr("QmlWidgets")QmlGraphicsView {anchors.fill: parent}
}
步骤5:运行应用程序

最后,在main.cpp中启动应用程序,加载QML界面,并在需要时添加国际化支持。

完整代码
#pragma once#include <QApplication>
#include <QDebug>
#include <QEvent>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QQuickPaintedItem>
#include <QQuickWindow>
#include <QPainter>
#include <QGraphicsSceneMouseEvent>/*#
ref https://het.as.utexas.edu/HET/Software/html/qtdeclarative.html
ref https://doc.qt.io/qt-5/qtquick-porting-qt5.html
ref https://github.com/KDABLabs/DeclarativeWidgets
ref https://www.qt.io/blog/2017/01/19/should-you-be-using-qgraphicsviewhttps://qmlbook.github.io/#
https://github.com/machinekit/QtQuickVcp
https://github.com/FabriceSalvaire/qt5-vector-graphic-shaders
https://box2d.org/https://www.learnqt.guide/working-with-events# 可参考 qtcharts QML 组件,它使用图形视图框架移植到QML图表。
https://github.com/qt/qtcharts/tree/dev*/
class QmlGraphicsView : public QQuickPaintedItem
{Q_OBJECTpublic:QmlGraphicsView(QQuickItem* parent = nullptr): QQuickPaintedItem(parent) {// Set item flagssetFlag(ItemHasContents, true);// Initialize the GraphicsScenem_scene = new QGraphicsScene(this);setAntialiasing(QQuickItem::antialiasing());connect(m_scene, &QGraphicsScene::changed, this, &QmlGraphicsView::sceneChanged);connect(this, &QmlGraphicsView::needRender, this, &QmlGraphicsView::renderScene, Qt::QueuedConnection);connect(this, SIGNAL(antialiasingChanged(bool)), this, SLOT(handleAntialiasingChanged(bool)));// add Textm_scene->addText("Hello, world!\ncheungxiongwei");m_scene->addRect(1, 1, 85, 32);setAcceptedMouseButtons(Qt::AllButtons);setAcceptHoverEvents(true);}~QmlGraphicsView() { delete m_sceneImage; }signals:public:void paint(QPainter* painter) override {if(m_sceneImage && painter) {auto pos = boundingRect().center() - m_scene->sceneRect().center();painter->drawImage(pos, *m_sceneImage);}}Q_SIGNALS:void needRender();
private Q_SLOTS:void handleAntialiasingChanged(bool enable) {setAntialiasing(enable);emit needRender();}void sceneChanged(QList<QRectF> region) {const int count       = region.size();const qreal limitSize = 0.01;if(count && !m_updatePending) {qreal totalSize = 0.0;for(int i = 0; i < count; i++) {const QRectF& reg = region.at(i);totalSize += (reg.height() * reg.width());if(totalSize >= limitSize) break;}// Ignore region updates that change less than small fraction of a pixel,// as there is little point regenerating the image in these cases. These// are typically cases where OpenGL series are drawn to otherwise static// view.if(totalSize >= limitSize) {m_updatePending = true;// Do async render to avoid some unnecessary renders.emit needRender();} else {// We do want to call update to trigger possible gl series updates.update();}}}void renderScene() {m_updatePending = false;QSize viewSize = size().toSize();if(!m_sceneImage || viewSize != m_sceneImage->size()) {delete m_sceneImage;qreal dpr    = window() ? window()->devicePixelRatio() : 1.0;m_sceneImage = new QImage(viewSize * dpr, QImage::Format_ARGB32);m_sceneImage->setDevicePixelRatio(dpr);m_sceneImageNeedsClear = true;}if(m_sceneImageNeedsClear) {m_sceneImage->fill(Qt::transparent);}QPainter painter(m_sceneImage);if(antialiasing()) {painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);}QRect renderRect(QPoint(0, 0), viewSize);m_scene->render(&painter, renderRect, renderRect);update();}protected:void mousePressEvent(QMouseEvent* event) override {m_mousePressScenePoint     = event->pos();m_mousePressScreenPoint    = event->globalPos();m_lastMouseMoveScenePoint  = m_mousePressScenePoint;m_lastMouseMoveScreenPoint = m_mousePressScreenPoint;m_mousePressButton         = event->button();m_mousePressButtons        = event->buttons();QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMousePress);mouseEvent.setWidget(0);mouseEvent.setButtonDownScenePos(m_mousePressButton, m_mousePressScenePoint);mouseEvent.setButtonDownScreenPos(m_mousePressButton, m_mousePressScreenPoint);mouseEvent.setScenePos(m_mousePressScenePoint);mouseEvent.setScreenPos(m_mousePressScreenPoint);mouseEvent.setLastScenePos(m_lastMouseMoveScenePoint);mouseEvent.setLastScreenPos(m_lastMouseMoveScreenPoint);mouseEvent.setButtons(m_mousePressButtons);mouseEvent.setButton(m_mousePressButton);mouseEvent.setModifiers(event->modifiers());mouseEvent.setAccepted(false);QApplication::sendEvent(m_scene, &mouseEvent);update();}void mouseReleaseEvent(QMouseEvent* event) override {QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseRelease);mouseEvent.setWidget(0);mouseEvent.setButtonDownScenePos(m_mousePressButton, m_mousePressScenePoint);mouseEvent.setButtonDownScreenPos(m_mousePressButton, m_mousePressScreenPoint);mouseEvent.setScenePos(event->pos());mouseEvent.setScreenPos(event->globalPos());mouseEvent.setLastScenePos(m_lastMouseMoveScenePoint);mouseEvent.setLastScreenPos(m_lastMouseMoveScreenPoint);mouseEvent.setButtons(event->buttons());mouseEvent.setButton(event->button());mouseEvent.setModifiers(event->modifiers());mouseEvent.setAccepted(false);QApplication::sendEvent(m_scene, &mouseEvent);m_mousePressButtons = event->buttons();m_mousePressButton  = Qt::NoButton;update();}void hoverMoveEvent(QHoverEvent* event) override {QPointF previousLastScenePoint = m_lastMouseMoveScenePoint;// Convert hover move to mouse move, since we don't seem to get actual mouse move events.// QGraphicsScene generates hover events from mouse move events, so we don't need// to pass hover events there.QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);mouseEvent.setWidget(0);mouseEvent.setButtonDownScenePos(m_mousePressButton, m_mousePressScenePoint);mouseEvent.setButtonDownScreenPos(m_mousePressButton, m_mousePressScreenPoint);mouseEvent.setScenePos(event->pos());// Hover events do not have global pos in them, and the screen position doesn't seem to// matter anyway in this use case, so just pass event pos instead of trying to// calculate the real screen position.mouseEvent.setScreenPos(event->pos());mouseEvent.setLastScenePos(m_lastMouseMoveScenePoint);mouseEvent.setLastScreenPos(m_lastMouseMoveScreenPoint);mouseEvent.setButtons(m_mousePressButtons);mouseEvent.setButton(m_mousePressButton);mouseEvent.setModifiers(event->modifiers());m_lastMouseMoveScenePoint  = mouseEvent.scenePos();m_lastMouseMoveScreenPoint = mouseEvent.screenPos();mouseEvent.setAccepted(false);QApplication::sendEvent(m_scene, &mouseEvent);// Update triggers another hover event, so let's not handle successive hovers at same// position to avoid infinite loop.if(previousLastScenePoint != m_lastMouseMoveScenePoint) {update();}}void mouseDoubleClickEvent(QMouseEvent* event) override {m_mousePressScenePoint     = event->pos();m_mousePressScreenPoint    = event->globalPos();m_lastMouseMoveScenePoint  = m_mousePressScenePoint;m_lastMouseMoveScreenPoint = m_mousePressScreenPoint;m_mousePressButton         = event->button();m_mousePressButtons        = event->buttons();QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseDoubleClick);mouseEvent.setWidget(0);mouseEvent.setButtonDownScenePos(m_mousePressButton, m_mousePressScenePoint);mouseEvent.setButtonDownScreenPos(m_mousePressButton, m_mousePressScreenPoint);mouseEvent.setScenePos(m_mousePressScenePoint);mouseEvent.setScreenPos(m_mousePressScreenPoint);mouseEvent.setLastScenePos(m_lastMouseMoveScenePoint);mouseEvent.setLastScreenPos(m_lastMouseMoveScreenPoint);mouseEvent.setButtons(m_mousePressButtons);mouseEvent.setButton(m_mousePressButton);mouseEvent.setModifiers(event->modifiers());mouseEvent.setAccepted(false);QApplication::sendEvent(m_scene, &mouseEvent);update();}private:QGraphicsScene* m_scene {nullptr};QPointF m_mousePressScenePoint;QPoint m_mousePressScreenPoint;QPointF m_lastMouseMoveScenePoint;QPoint m_lastMouseMoveScreenPoint;Qt::MouseButton m_mousePressButton;Qt::MouseButtons m_mousePressButtons;QImage* m_sceneImage {nullptr};bool m_updatePending {false};bool m_sceneImageNeedsClear {false};
};

代码仓库
https://gitcode.net/cheungxiongwei/qmlwidgets

总结

通过以上步骤,您可以在QML中成功集成图形视图框架,创建交互式的图形界面。这使您能够轻松地管理和展示2D图形元素,为用户提供出色的图形体验。

无论是游戏开发、数据可视化还是其他需要图形界面的应用程序,Qt的图形视图框架为开发者提供了一个强大的工具,使其能够以直观和交互式的方式与用户进行互动。

希望本文对您理解如何在QML中使用图形视图框架提供了一些帮助。如果您想深入学习和探索这个主题,可以查看Qt官方文档和示例代码。祝您在Qt开发中取得成功!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数学建模Matlab之基础操作

作者由于后续课程也要学习Matlab&#xff0c;并且之前也进行了一些数学建模的练习&#xff08;虽然是论文手&#xff09;&#xff0c;所以花了几天零碎时间学习Matlab的基础操作&#xff0c;特此整理。 基本运算 a55 %加法&#xff0c;同理减法 b2^3 %立方 c5*2 %乘法 x 1; …

Qt 综合练习小项目--反金币(2/2)

目录 4 选择关卡场景 4.2 背景设置 4.3 创建返回按钮 4.3 返回按钮 4.4 创建选择关卡按钮 4.5 创建翻金币场景 5 翻金币场景 5.1 场景基本设置 5.2 背景设置 5.3 返回按钮 5.4 显示当前关卡 5.5 创建金币背景图片 5.6 创建金币类 5.6.1 创建金币类 MyCoin 5.6.…

WPF绑定单变量Binding和绑定多变量MultiBinding 字符串格式化 UI绑定数据,数据变化自动更新UI,UI变化自动更新数据

UI绑定数据&#xff0c;数据变化自动更新UI&#xff0c;UI变化自动更新数据。 支持多设备&#xff0c;同时下载。 绑定单变量 在WPF (Windows Presentation Foundation) 中&#xff0c;您可以使用数据绑定来将变量绑定到界面元素。这允许您在界面上显示变量的值&#xff0c;…

SpringCloud-Bus

接上文 SpringCloud-消息组件 1 注册Bus Bus需要基于一个具体的消息队列实现&#xff0c;比如RabbitMQ.还使用最开始的服务拆分项目&#xff0c;比如现在借阅服务的某个接口调用时&#xff0c;能给用户服务和图书服务发送一个通知。 首先父项目导入SpringCloud依赖 <depend…

【网络安全-信息收集】网络安全之信息收集和信息收集工具讲解

一&#xff0c;域名信息收集 1-1 域名信息查询 可以用一些在线网站进行收集&#xff0c;比如站长之家 域名Whois查询 - 站长之家站长之家-站长工具提供whois查询工具&#xff0c;汉化版的域名whois查询工具。https://whois.chinaz.com/ 可以查看一下有没有有用的信息&#xf…

全志ARM926 Melis2.0系统的开发指引⑥

全志ARM926 Melis2.0系统的开发指引⑥ 编写目的9. 系统启动流程9.1. Shell 部分9.2.Orange 和 desktop 部分9.3. app_root 加载部分9.4. home 加载部分 10. 显示相关知识概述10.1. 总体结构10.2. 显示过程10.3. 显示宽高参数关系 -. 全志相关工具和资源-.1 全志固件镜像修改工具…

2023/10/4 QT实现TCP服务器客户端搭建

服务器端&#xff1a; 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> #include <QTcpSocket> #include <QList> #include <QMessageBox> #include <QDebug>QT_BEGIN_NAMESPACE namespace Ui { cla…

C++设计模式-生成器(Builder)

目录 C设计模式-生成器&#xff08;Builder&#xff09; 一、意图 二、适用性 三、结构 四、参与者 五、代码 C设计模式-生成器&#xff08;Builder&#xff09; 一、意图 将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 二、…

《计算机视觉中的多视图几何》笔记(13)

13 Scene planes and homographies 本章主要讲述两个摄像机和一个世界平面之间的射影几何关系。 我们假设空间有一平面 π \pi π&#xff0c;平面上的一点为 x π x_{\pi} xπ​。 x π x_{\pi} xπ​分别在两幅图像 P , P ′ P, P P,P′上形成了 x , x ′ x, x x,x′。 那…

JavaEE 网络原理——TCP的工作机制(中篇 三次握手和四次挥手)

文章目录 一、TCP 内部工作机制——连接管理1. 连接(三次握手)(1).有连接和确认应答之间的关系(2). 通过客户端和服务器详细描述三次握手 2. 断开连接(四次挥手)(1)讨论“四次握手”中间步骤的合并问题。(2) 根据简单的 TCP 代码解释断开连接(3) 四次挥手中的两个重要的 TCP 状…

@ConfigurationProperties配置绑定~

ConfigurationProperties注解是Spring Boot中的一个注解&#xff0c;用于将配置文件中的属性值绑定到Java类中的字段上。 ConfigurationProperties注解的作用包括&#xff1a; 实现配置文件属性和Java类字段的映射&#xff0c;简化了读取配置文件的操作。 可以指定配置文件中…

React项目部署 - Nginx配置

写在前面&#xff1a;博主是一只经过实战开发历练后投身培训事业的“小山猪”&#xff0c;昵称取自动画片《狮子王》中的“彭彭”&#xff0c;总是以乐观、积极的心态对待周边的事物。本人的技术路线从Java全栈工程师一路奔向大数据开发、数据挖掘领域&#xff0c;如今终有小成…

GB28181学习(六)——实时视音频点播(数据传输部分)

GB28181系列文章&#xff1a; 总述&#xff1a;https://blog.csdn.net/www_dong/article/details/132515446 注册与注销&#xff1a;https://blog.csdn.net/www_dong/article/details/132654525 心跳保活&#xff1a;https://blog.csdn.net/www_dong/article/details/132796…

GPT系列论文解读:GPT-2

GPT系列 GPT&#xff08;Generative Pre-trained Transformer&#xff09;是一系列基于Transformer架构的预训练语言模型&#xff0c;由OpenAI开发。以下是GPT系列的主要模型&#xff1a; GPT&#xff1a;GPT-1是于2018年发布的第一个版本&#xff0c;它使用了12个Transformer…

企业微信机器人对接GPT

现在网上大部分微信机器人项目都是基于个人微信实现的&#xff0c;常见的类库都是模拟网页版微信接口。 个人微信作为我们自己日常使用的工具&#xff0c;也用于支付场景&#xff0c;很怕因为违规而被封。这时&#xff0c;可以使用我们的企业微信机器人&#xff0c;利用企业微信…

【数据结构】排序(1) ——插入排序 希尔排序

目录 一. 直接插入排序 基本思想 代码实现 时间和空间复杂度 稳定性 二. 希尔排序 基本思想 代码实现 时间和空间复杂度 稳定性 一. 直接插入排序 基本思想 把待排序的记录按其关键码值的大小依次插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&…

程序三高的方法

程序三高的方法 目录概述需求&#xff1a; 设计思路实现思路分析1.1&#xff09;高并发 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for change,c…

全志ARM926 Melis2.0系统的开发指引⑤

全志ARM926 Melis2.0系统的开发指引⑤ 编写目的8. 固件修改工具(ImageModify)使用8.1.界面说明8.2.操作步骤8.2.1. 配置平台8.2.2. 选择固件8.2.3. 选择要替换的文件8.2.4. 替换文件8.2.5. 保存固件 8.3.注意事项8.4.增加固件修改权限设置8.4.1. 概述8.4.2. 操作说明8.4.2.1.打…

竞赛选题 机器视觉目标检测 - opencv 深度学习

文章目录 0 前言2 目标检测概念3 目标分类、定位、检测示例4 传统目标检测5 两类目标检测算法5.1 相关研究5.1.1 选择性搜索5.1.2 OverFeat 5.2 基于区域提名的方法5.2.1 R-CNN5.2.2 SPP-net5.2.3 Fast R-CNN 5.3 端到端的方法YOLOSSD 6 人体检测结果7 最后 0 前言 &#x1f5…

Jetpack生命周期感知组件ViewModel

ViewModel Jetpack ViewModel是Android Jetpack组件库中的一个组件&#xff0c;用于帮助开发者管理UI相关的数据和状态。ViewModel的主要作用是存储和管理与UI相关的数据&#xff0c;以及处理UI的状态变化。 使用ViewModel可以解决以下问题&#xff1a; 避免配置变更&#x…