我们将要用到三个类,QGraphicsView(视图类)、QGraphicsScene(场景类)、QGraphicsItem(图元类)。
继承QWidget类,与其他类一样,以窗口的左上角作为自己坐标系的原点,主要用于渲染显示场景中的图元,支持OpenGL渲染工作。
坐标系以中心作为自己的原点
如果调用paint()函数重绘图元时,则以此坐标系为基准
接下来我们实现以下的案例
该项目具有旋转、缩放、倾斜功能
首先我们创建一个QWidget工程
然后继续创建一个C++Class类,该类继承QGraphicsItem类,取名为“PixItem”
首先我们看pixitem.h文件
#ifndef PIXITEM_H
#define PIXITEM_H
#include
#include
#include
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
这个纯虚函数将项目的外部边界定义为矩形;所有的绘制必须限制在一个项目的边界范围内,QGraphicsView使用这个来确定项目是否需要重画。
尽管项目的形状可以是任意的,但边界矩形始终是矩形,并且不受项目转换的影响。
如果你想改变项目的边界矩形,你必须首先调用prepareGeometryChange()。这会通知场景即将发生的更改,以便它可以更新其项目几何索引;否则,场景将不知道项目的新几何形状,并且结果是未定义的(通常,渲染工件留在视图中)。
重新实现这个函数,让QGraphicsView确定小部件的哪些部分(如果有的话)需要重新绘制。
注意:对于绘制轮廓/笔画的形状,在边界矩形中包含笔宽度的一半是很重要的,但是没有必要补偿抗锯齿。
这个函数通常由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
#include"pixitem.h"
#include
#include
#include
#include
#include
#include
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QWidget
{
Q_OBJECT
public:
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
类型定义为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;
}
代码实现了一个图形界面,包含一个可以旋转、缩放、倾斜的图片。具体实现过程如下:
这个属性保存了场景矩形;场景的边界矩形
场景矩形定义了场景的范围。它主要由QGraphicsView用于确定视图的默认可滚动区域,并由QGraphicsScene用于管理项目索引。
如果未设置,或者设置为空QRectF, scen直立()将返回自场景创建以来场景中所有项目的最大边界矩形(即,当项目添加到场景中或在场景中移动时,矩形会增长,但不会缩小)。
这是一个重载函数。
这个方便的函数相当于调用setPos(QPointF(x, y))。
将项目的位置设置为pos,它位于父坐标中。对于没有父项的项目,pos在场景坐标中。
项目的位置在父坐标中描述了它的原点(本地坐标(0,0))。
将当前场景设置为场景。如果已经在查看场景,则此函数不执行任何操作。
当在视图上设置场景时,QGraphicsScene::changed()信号自动连接到该视图的updateScene()插槽,并且视图的滚动条被调整以适应场景的大小。
视图不占有场景的所有权。
这个属性保存滑块的方向
方向必须是Qt::Vertical(默认)或Qt::Horizontal。
设置滑块的最小值为min,最大值为max。
如果max小于min,则min成为唯一合法的值。
顺时针旋转当前视图变换角度度。
按(sx, sy)缩放当前视图转换。
通过(sh, sv)剪切当前视图转换。
pow函数为求次幂函数.