二十五、图形视图框架

二十五、图形视图框架

我们将要用到三个类,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。为了保证…

IO / 标准IO 和 文件IO 的总结

我将标准IO和文件IO有关概念、api总结在一张表格了&#xff0c;方便查找使用 标准IO 文件IO 概念 使用库函数实现&#xff0c;将内核提供的IO函数接口进行了再次封装&#xff0c;因为有缓冲区&#xff0c;所以效率比文件IO高 对文件进行操作&#xff0c;使用的是文件指针来…

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

如何选择深度学习推理框架&#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…

golang 基于数组、切片、链表实现队列

数组 package mainimport ("errors""fmt" )func main() {// 创建一个简单队列// 如果head tail 队列空// 如果tail len(array) - 1// 整体做迁移 如果head 0 队列满stack1 : createQueue[int]()err : stack1.push(1)// 处理错误 后面的就不处理了if er…

Ajax原理以及优缺点

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

Java----冒泡排序、选择排序、插入排序、快速排序、堆排序

int[] arr {4, 2, 7, 1, 5, 9, 3, 6, 8}; 冒泡排序 for(int i 0; i < arr.length-1; i) //外循环是控制排序的次数n-1, 每次循环结束确定一个最大值{for(int j 0; j < arr.length - 1 - i; j) // 内循环是第i次循环中比较的次数n-i{if(arr[j] > arr[j1]){//前面一…

LeetCode-23. 合并 K 个升序链表

问题分析 先建立一个小顶堆将每一路的最小元素都加入小顶堆&#xff0c;此时堆顶元素就是全局的最小值将堆顶元素弹出。若堆顶元素所在的数组不为空&#xff0c;则将下一元素加入堆中重复2、3操作&#xff0c;直到所有数据都读取完毕将堆内元素按顺序读出&#xff0c;并清空堆…

双系统安装显卡驱动

安装步骤 更新系统: 在安装任何新软件之前&#xff0c;最好先更新系统&#xff0c;以确保所有依赖都是最新的。打开终端&#xff08;Terminal&#xff09;并运行以下命令&#xff1a; sudo apt update sudo apt upgrade关闭Nouveau驱动: Nouveau是Nvidia显卡的开源驱动&#xf…

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

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

跳跃游戏 + 45. 跳跃游戏 II

给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输…

动态SQL学习及使用场景(简略)

假设我们有一个商品表&#xff0c;包含id、name、price和category四个字段。现在需要实现修改商品价格的功能&#xff0c;我们可以使用动态SQL实现。 首先&#xff0c;我们需要构造一个SQL语句&#xff0c;根据用户提供的参数来动态生成&#xff0c;具体实现如下&#xff1a; …

三、Shell 环境

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

Tomcat指定jdk启动

要在Tomcat中指定使用特定的JDK启动&#xff0c;可以按照以下步骤进行操作&#xff1a; 确保你已经安装了所需的JDK&#xff0c;并且知道其安装路径。 打开Tomcat的安装目录&#xff0c;在bin目录下找到catalina.bat&#xff08;Windows&#xff09;或catalina.sh&#xff08;…

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

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

2023.12.6 关于flask中的route、render_template、redirect的关系问题

2023.12.6 关于flask中的route、render_template、redirect的关系问题 之前对于route、render_template、redirect三者的关系还有一些模糊&#xff0c;测试了一个案例后就比较清晰了&#xff0c;简单来说就是路径、模板和重定向&#xff0c;三者相对独立&#xff0c;只是一般命…

我的创作纪念日-第四年

机缘 不知不觉&#xff0c;CSDN 写博客已经四年了&#xff0c;也伴随了我读研读博的绝大多数时间。最多的时候&#xff0c;还是想记录下自己所走过的路程吧&#xff0c;然后留给后人一点经验借鉴。 实战项目中的经验分享   应该只分享过一篇博文&#xff1a;基于Jetson nan…