二十五、图形视图框架

二十五、图形视图框架

我们将要用到三个类,QGraphicsView(视图类)、QGraphicsScene(场景类)、QGraphicsItem(图元类)。

QGraphicsView(视图类)

继承QWidget类,与其他类一样,以窗口的左上角作为自己坐标系的原点,主要用于渲染显示场景中的图元,支持OpenGL渲染工作。

QGraphicsScene(场景类)

坐标系以中心作为自己的原点

QGraphicsItem(图元类)

如果调用paint()函数重绘图元时,则以此坐标系为基准

接下来我们实现以下的案例

该项目具有旋转、缩放、倾斜功能

首先我们创建一个QWidget工程

然后继续创建一个C++Class类,该类继承QGraphicsItem类,取名为“PixItem” 

首先我们看pixitem.h文件

#ifndef PIXITEM_H
#define PIXITEM_H#include<QGraphicsItem>
#include<QPixmap>
#include<QPainter>class PixItem : public QGraphicsItem
{public:PixItem(QPixmap *pixmap);QRectF boundingRect() const;void paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget);private:QPixmap pix;};#endif // PIXITEM_H

QRectF QGraphicsItem::boundingRect() const:

这个纯虚函数将项目的外部边界定义为矩形;所有的绘制必须限制在一个项目的边界范围内,QGraphicsView使用这个来确定项目是否需要重画。
尽管项目的形状可以是任意的,但边界矩形始终是矩形,并且不受项目转换的影响。

如果你想改变项目的边界矩形,你必须首先调用prepareGeometryChange()。这会通知场景即将发生的更改,以便它可以更新其项目几何索引;否则,场景将不知道项目的新几何形状,并且结果是未定义的(通常,渲染工件留在视图中)。
重新实现这个函数,让QGraphicsView确定小部件的哪些部分(如果有的话)需要重新绘制。

注意:对于绘制轮廓/笔画的形状,在边界矩形中包含笔宽度的一半是很重要的,但是没有必要补偿抗锯齿。

void QGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = ...):

这个函数通常由QGraphicsView调用,它用局部坐标绘制项的内容 。

在QGraphicsItem子类中重新实现此函数,以使用painter提供该项的绘制实现。option参数为项目提供样式选项,例如其状态、暴露区域和详细级别提示。widget参数是可选的。如果提供,则指向正在绘制的小部件;否则,它是0。对于缓存的绘画,widget总是0。

pixitem.cpp

#include "pixitem.h"PixItem::PixItem(QPixmap *pixmap)
{pix=*pixmap;
}QRectF PixItem::boundingRect() const
{return QRectF(-2-pix.width()/2,-2-pix.height()/2,pix.width()+4,pix.height()+4);
}void PixItem::paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget)
{painter->drawPixmap(-pix.width()/2,-pix.height()/2,pix);
}

boundingRect()函数:该函数返回一个QRectF类型的矩形,用于描述PixItem的边界矩形。该矩形的左上角坐标为(-2-pix.width()/2,-2-pix.height()/2),宽度为pix.width()+4,高度为pix.height()+4。

paint()函数:该函数用于绘制PixItem。在该函数中,首先调用painter->drawPixmap()函数绘制pix图像,该函数的参数为(-pix.width()/2,-pix.height()/2)表示图像的左上角坐标。

widget.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QWidget>#include"pixitem.h"
#include<math.h>
#include<QGraphicsView>
#include<QGraphicsScene>
#include<QFrame>
#include<QVBoxLayout>
#include<QHBoxLayout>
#include<QGroupBox>
#include<QSlider>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QWidget
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();void createControlFrameFunc(); //创建控件框架private:Ui::MainWindow *ui;int angle; //角度qreal scaleValue; //缩放qreal leanValue; //倾斜QGraphicsView *view;QFrame *controlFrame; //控制边框样式PixItem *pixitem;private slots:void rotateFunc(int); //旋转void scaleFunc(int);void leanFunc(int);
};
#endif // MAINWINDOW_H

typedef qreal:

类型定义为double,除非Qt配置了-qreal float选项。

widget.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QWidget(parent), ui(new Ui::MainWindow)
{//ui->setupUi(this);setWindowTitle("图形测试");angle=3;scaleValue=3;leanValue=3;//场景QGraphicsScene *scene=new QGraphicsScene;scene->setSceneRect(-200,-200,380,380);QPixmap *pixmap=new QPixmap("E:/blog/source/img/wallhaven-gp7mq3.jpg");//图元pixitem=new PixItem(pixmap);scene->addItem(pixitem);pixitem->setPos(0,0);//视图view=new QGraphicsView();view->setScene(scene);view->setMinimumSize(800,600);controlFrame=new QFrame;createControlFrameFunc();//主窗体布局设计QHBoxLayout *hbl=new QHBoxLayout(this);hbl->addWidget(view);hbl->addWidget(controlFrame);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::createControlFrameFunc()
{//旋转QSlider *rotateSlider=new QSlider;rotateSlider->setOrientation(Qt::Horizontal);rotateSlider->setRange(0,360);QHBoxLayout *rotateLayout=new QHBoxLayout;rotateLayout->addWidget(rotateSlider);QGroupBox *rotateGroup=new QGroupBox("图形旋转");rotateGroup->setLayout(rotateLayout);//缩放QSlider *scalesilder=new QSlider;scalesilder->setOrientation(Qt::Horizontal);scalesilder->setRange(0,2*scaleValue);scalesilder->setValue(scaleValue);QHBoxLayout *scalelayout=new QHBoxLayout;scalelayout->addWidget(scalesilder);QGroupBox *scalegroup=new QGroupBox("图形缩放");scalegroup->setLayout(scalelayout);//倾斜QSlider *leansilder = new QSlider;leansilder->setOrientation(Qt::Horizontal);leansilder->setRange(0,2*leanValue);leansilder->setValue(leanValue);QHBoxLayout *leanlayout = new QHBoxLayout;leanlayout->addWidget(leansilder);QGroupBox *leangroup = new QGroupBox(tr("图形倾斜"));leangroup->setLayout(leanlayout);connect(rotateSlider,SIGNAL(valueChanged(int)),this,SLOT(rotateFunc(int)));connect(scalesilder,SIGNAL(valueChanged(int)),this,SLOT(scaleFunc(int)));connect(leansilder,SIGNAL(valueChanged(int)),this,SLOT(leanFunc(int)));// 控制面板设计布局QVBoxLayout *vlayoutframe=new QVBoxLayout;vlayoutframe->addWidget(rotateGroup);vlayoutframe->addWidget(scalegroup);vlayoutframe->addWidget(leangroup);controlFrame->setLayout(vlayoutframe);}void MainWindow::rotateFunc(int val)
{view->rotate(val-angle);angle=val;
}void MainWindow::scaleFunc(int val)
{qreal qr;if(val>scaleValue){qr=pow(1.1,(val-scaleValue));}else{qr=pow(1/1.1,(scaleValue-val));}view->scale(qr,qr);scaleValue=val;
}void MainWindow::leanFunc(int val)
{view->shear((val-leanValue)/2.0,0);leanValue=val;
}

代码实现了一个图形界面,包含一个可以旋转、缩放、倾斜的图片。具体实现过程如下:

  1. 创建一个QGraphicsScene对象,设置其大小为(-200,-200,380,380)。
  2. 创建一个QPixmap对象,加载一张图片。
  3. 创建一个PixItem对象,将QPixmap对象作为参数传入,然后将PixItem对象添加到QGraphicsScene对象中。
  4. 创建一个QGraphicsView对象,将QGraphicsScene对象作为参数传入,然后设置QGraphicsView对象的最小大小为(800,600)。
  5. 创建一个QFrame对象,调用createControlFrameFunc()函数创建一个控制面板。
  6. 创建一个水平布局QHBoxLayout对象,将QGraphicsView对象和QFrame对象添加到该布局中。
  7. 将QHBoxLayout对象设置为主窗口的布局。
  8. 在createControlFrameFunc()函数中,创建三个QSlider对象,分别用于控制旋转、缩放、倾斜。
  9. 创建三个QHBoxLayout对象,将QSlider对象添加到对应的布局中。
  10. 创建三个QGroupBox对象,将对应的布局添加到QGroupBox对象中。
  11. 将三个QGroupBox对象添加到一个垂直布局QVBoxLayout对象中。
  12. 将QVBoxLayout对象设置为QFrame对象的布局。
  13. 通过connect()函数将QSlider对象的valueChanged()信号与对应的槽函数rotateFunc()、scaleFunc()、leanFunc()连接起来。
  14. 在rotateFunc()函数中,调用QGraphicsView对象的rotate()函数实现旋转。
  15. 在scaleFunc()函数中,根据QSlider对象的值计算缩放比例,然后调用QGraphicsView对象的scale()函数实现缩放。
  16. 在leanFunc()函数中,调用QGraphicsView对象的shear()函数实现倾斜。


void setSceneRect(qreal x, qreal y, qreal w, qreal h):

这个属性保存了场景矩形;场景的边界矩形
场景矩形定义了场景的范围。它主要由QGraphicsView用于确定视图的默认可滚动区域,并由QGraphicsScene用于管理项目索引。
如果未设置,或者设置为空QRectF, scen直立()将返回自场景创建以来场景中所有项目的最大边界矩形(即,当项目添加到场景中或在场景中移动时,矩形会增长,但不会缩小)。

void QGraphicsItem::setPos(qreal x, qreal y):

这是一个重载函数。
这个方便的函数相当于调用setPos(QPointF(x, y))。

void QGraphicsItem::setPos(const QPointF &pos):

将项目的位置设置为pos,它位于父坐标中。对于没有父项的项目,pos在场景坐标中。
项目的位置在父坐标中描述了它的原点(本地坐标(0,0))。
 

void QGraphicsView::setScene(QGraphicsScene *scene):

将当前场景设置为场景。如果已经在查看场景,则此函数不执行任何操作。
当在视图上设置场景时,QGraphicsScene::changed()信号自动连接到该视图的updateScene()插槽,并且视图的滚动条被调整以适应场景的大小。
视图不占有场景的所有权。


void setOrientation(Qt::Orientation):

这个属性保存滑块的方向
方向必须是Qt::Vertical(默认)或Qt::Horizontal。

void QAbstractSlider::setRange(int min, int max):

设置滑块的最小值为min,最大值为max。
如果max小于min,则min成为唯一合法的值。

void QGraphicsView::rotate(qreal angle):

顺时针旋转当前视图变换角度度。

void QGraphicsView::scale(qreal sx, qreal sy):

按(sx, sy)缩放当前视图转换。

void QGraphicsView::shear(qreal sh, qreal sv) :

通过(sh, sv)剪切当前视图转换。

pow函数为求次幂函数.

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

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

相关文章

玩转Docker(一):容器生态系统

文章目录 一、核心技术二、平台技术三、支持技术 本文结构如下&#xff1a; 一、核心技术 容器核心技术是指能够让Container在host上运行起来的那些技术。 &#xff08;1&#xff09;容器规范 容器不光是Docker&#xff0c;还有其他容器&#xff0c;比如CoreOS的rkt。为了保证…

网络推理之深度学习推理框架

如何选择深度学习推理框架&#xff1f; PyTorch vs LibTorch&#xff1a;网络推理速度谁更快&#xff1f; 高质量C进阶[2]&#xff1a;如何让线性代数加速1000倍&#xff1f; TensorRT: ONNX:

微服务--07--Sentienl中使用的限流算法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Sentienl中使用的限流算法1、计数器固定窗口算法2、计数器滑动窗口算法----&#xff08;默认&#xff09;3、漏桶算法----&#xff08;排队等待&#xff09;4、令牌…

node.js 启一个前端代理服务,代码直接改一改拿来用

文章目录 前言一、分析技术二、操作步骤2.1、下载依赖2.2、创建一个 serve.js 文件2.3、js 文件中写入以下代码 三、运行&#xff1a; node serve四、结果展示五、总结六、感谢 前言 有时候我们需要做一些基础的页面时&#xff0c;在研发过程中需要代理调用接口避免浏览器跨域…

AI全栈大模型工程师(二十六)如何选择 GPU 和云服务厂商

&#x1f4a1; 这节课会带给你 如何选择 GPU 和云服务厂商&#xff0c;追求最高性价比 如何部署自己 fine-tune 的模型&#xff0c;向业务提供高可用推理服务 如何控制内容安全&#xff0c;做好算法备案&#xff0c;确保合规 开始上课&#xff01; 硬件选型 当我们为模型训练及…

电子学会C/C++编程等级考试2022年12月(五级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:漫漫回国路 2020年5月,国际航班机票难求。一位在美国华盛顿的中国留学生,因为一些原因必须在本周内回到北京。现在已知各个机场之间的航班情况,求问他回不回得来(不考虑转机次数和机票价格)。 时间限制:1000 内存限制:655…

Ajax原理以及优缺点

Ajax原理 1.Ajax的原理简单来说是在用户和服务器之间加了—个中间层(AJAX引擎)&#xff0c;通过XmlHttpRequest对象来向服务器发异步请求&#xff0c; 2.从服务器获得数据&#xff0c;然后用javascript来操作DOM而更新页面。使用户操作与服务器响应异步化。 3.这其中最关键的一…

Linux系统使用ESP8266开发板(CP2102)

连接ESP8266开发板到电脑 虚拟机选择开发板硬件连接 查看USB连接情况: lsusb 授权USB接口访问 成功连接 编译项目 上传到开发板 成功提供WIFI热点服务

三、Shell 环境

一、Linux 系统分类 在 Linux 中&#xff0c;常见的 Shell 有以下几种&#xff1a; Bourne Shell&#xff08;sh&#xff09;&#xff1a;最早的 Shell&#xff0c;由 Stephen Bourne 开发。它是大多数其他 Shell 的基础。Bourne Again Shell&#xff08;bash&#xff09;&am…

thinkphp6入门(13)-- 一对多关联模型

定义一对一关联&#xff0c;例如&#xff0c;一个用户都有多个工作经历。 一、两表 1.用户表:user 2.工作经验表&#xff1a;work_experience user表的id关联work_experience表的user_id。 注意看&#xff0c;user_id1的有2条工作经验 二、数据模型 主表模型&#xff1a;…

如何在 1 天内将网站打造为手机app

为您的网站提供移动应用程序的重要性怎么强调都不为过。随着用户越来越依赖智能手机和平板电脑进行在线活动&#xff0c;将您的网站转变为移动手机app可以显着增强用户体验、提高参与度并扩大您的在线影响力。在这篇博客中&#xff0c;我们将探讨如何快速有效地将网站制作成移动…

【Let‘s Encrypt SSL】使用 acme.sh 给 Nginx 安装 Let’s Encrypt 提供的免费 SSL 证书

安装acme.sh 安装 acme.sh 并设置邮箱用来接受重要通知&#xff0c;如证书快过期未更新通知 curl https://get.acme.sh | sh -s emailmyexample.com执行命令后几秒就安装好了&#xff0c;如果半天没有反应请 CtrlC 后重新执行命令。acme.sh 安装在 ~/.acme.sh 目录下&#xf…

windows 10多用户同时远程登陆配置【笔记】

系统环境&多用户访问情况&#xff1a; 1、【win】【R】键入【gpedit.msc】 2、依次选择【计算机配置】→ 【管理模板】 → 【Windows组件】 → 【远程桌面服务】 → 【远程桌面会话主机】 →【连接】 2.1、右键 【允许用户通过使用远程桌面服务进行远程连接】 编辑 …

C++初阶-vector类的模拟实现

vector类的模拟实现 一、经典的vector类问题1.1 前期准备 二、vector的默认成员函数2.1 构造函数2.1.1 无参构造2.1.2 构造具有n个对象值为val的容器&#xff08;数据类型为模板类型T&#xff09;2.1.3 拷贝构造 2.2 swap&#xff08;operator需要用&#xff09;2.3 复制重载op…

volatile 系列之指令重排序导致的可见性问题

什么是指令重排序呢?为了更加直观地理解&#xff0c;老司机还是通过一个案例来说明 public class MemoryReorderingExample {private static int x0,y0:private static int a0,b0;public static void main(String[] args) throws InterruptedException {int i0;while(true){…

排序算法之一:直接插入排序

1.基本思想 直接插入排序是一种简单的插入排序法&#xff0c;其基本思想是&#xff1a; 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到一个新的有序序列 实际中我们玩扑克牌时&#xff0c;就用…

【UML】组件图中的供接口和需接口与面向对象中的接口

UML&#xff08;统一建模语言&#xff09;组件图中的“供接口”&#xff08;Provided Interface&#xff09;和“需接口”&#xff08;Required Interface&#xff09;与面向对象编程中的接口概念有关联&#xff0c;但它们在应用上有所区别。 下面解释两者的关系&#xff1a; …

NCNN 源码学习【一】:学习顺序

最近一段时间一直在做模型部署的工作&#xff0c;主要是利用NCNN部署到安卓端&#xff0c;跟着网上的博客和开源项目&#xff0c;做了很多工作&#xff0c;也学习到很多东西&#xff0c;但是对于NCNN的源码&#xff0c;并没有仔细的研究过&#xff0c;对我来说&#xff0c;仿佛…

C++共享和保护——(2)生存期

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 生命如同寓言&#xff0c;其价值不在于…

改进YOLOv8注意力系列二:结合CBAM、Coordinate Attention、deformable_LKA_Attention可变形大核注意力

改进YOLOv8注意力系列二:结合ACmix、Biformer、BAM注意力机制 代码CBAM注意力Coordinate Attention坐标注意力deformable_LKA_Attention可变形大核注意力加入方法各种yaml加入结构本文提供了改进 YOLOv8注意力系列包含不同的注意力机制以及多种加入方式,在本文中具有完整的代…