二十五、图形视图框架

二十五、图形视图框架

我们将要用到三个类,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_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

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函数为求次幂函数.

  • 10
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mo Yan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值