当前位置:   article > 正文

Qt5入门学习——图形视图框架_qt5图形视图框架学习

qt5图形视图框架学习


Graphics View(图形视图)框架结构取代了之前Qt版本中的QCanvas模块,它提供了基于图元的模型/视图编程,类似于QtInterView的模型/视图结果,只是这里的数据是图形。

图形视图体系结构

Graphics View框架结构的特点主要包含元素及坐标系统。

Graphics View的特点

Graphics View框架结构的主要特点如下:

  • Graphics View框架结构中,系统可以利用Qt绘图系统的反锯齿、OpenGL工具来改善绘图性能。
  • Graphics View支持事件传播体系,可以使图元在场景(scene)中的交互能力提高1倍,图元能够处理键盘事件和鼠标事件。其中,鼠标事件包含鼠标按下、移动、释放和双击,还可以跟踪鼠标的移动。
  • 在Graphics View框架中,通过二元空间划分树(Binary Space Partitioning, BSP)提供快速的图元查找,这样能够实时显示包含上百万个图元的大场景。

Graphics View的三元素

Graphics View框架结构主要包含三个类:场景类(QGraphicsScene)、视图类(QGraphicsView)和图元类(QGraphicsItem),统称为“三元素”。其中,场景类提供了一个用于管理位于其中的众多图元容器,视图类用于显示场景中的图元,一个场景可以通过多个视图表现,一个场景包括多个几何图形。它们三者这间关系如下:
在这里插入图片描述

  • 场景类:QGraphicsScene类
    这是一个用于放置图元的容器,本身是不可见的,必须通过与之相连的视图类来显示及与外界进行互操作。通过 QGraphicsScene::addItem()可以添加一个图元到场景中。图元可以通过多个函数进行检索。QGraphicsScene::items()和一些重载函数可以返回和点、矩形、多边形或向量路径相交的所有图元。QGraphicsScene::itemAt()返回指定点的顶层图元。
    场景类主要完成的工作包括提供对它包含的图元的操作接口和传递事件、管理各个图元的状态(如选择和焦点处理)、提供无变换的绘制功能(如打印)等。
    事件传播体系结构将场景事件发送给图元,同时管理图元之间的事件传递。如果场景接收到了在某一点的鼠标单击事件,场景会将事件传给这一点的图元。
    管理各个图元的状态(如选择和焦点处理)。可以通过QGraphicsScene::setSelectionArea()函数旋转图元,选择区域可以是任意的形状,使用QPainterPath表示。若要得到当前选择的图元列表,则可以使用函数QGraphicsScene::selectedItems()。可以通过QGraphicsScene::setFocusItem()函数或QGraphicsScene::setFocus()函数来设置图元的焦点,获得当前具有焦点的图元使用函数QGraphicsScene::focusItem()。
    如果需要将场景内容绘制到特定的绘图设备,则可以使用QGraphicsScene::render()函数在绘图设备上绘制场景。

  • 视图类:QGraphicsView类
    它提供一个可视的窗口,用于显示场景的图元。在同一个场景中可以有多个视图,也可以为相同的数据提供几种不同的视图。
    QGraphicsView是可滚动的窗口部件,可以提供滚动条来浏览大的场景。如果需要使用OpenGL,则可以使用QGraphicsView::setViewport()将视图设置成为QGLWideget。
    视图接收键盘和鼠标的输入事件,并将它们翻译为场景事件(将坐标转换为场景的坐标)。使用变换矩阵函数QGraphicsView::matrix()可以变换场景的坐标,实现场景的缩放和旋转。QGraphicsView提供QGraphicsView::mapToScene()和QGraphicsView::mapFromScene()用于与场景的坐标进行转换。

  • 图元类:QGraphicsItem类
    它是场景中各个图元的基类,在它的基础上可以继承出各种图元类,Qt已经预置的包括直线(QGraphicsLineItem)、椭圆(QGraphicsEllipseItem)、文本图元(QGraphicsTextItem)、矩形(QGraphicsRectItem)等。当然,也可以在QGraphicsItem类的基础上实现自定义的图元类。用户可以继承QGraphicsItem实现符合自己需要的图元。
    图元有自己的坐标系,也提供场景和图元。图元还可以通过QGraphicsItem::matrix()来进行自身的变换,可以包含子图元。
    QGraphicsItem主要有以下功能:

    • 处理鼠标按下、移动、释放、双击、悬停、滚轮和右键菜单事件。
    • 处理键盘输入事件。
    • 处理拖拽事件。
    • 分组。
    • 碰撞检测。

QGraphicsView的坐标系统

QGraphicsView坐标基于笛卡尔坐标系,一个图元的场景具有x坐标和y坐标。当使用没有变换的视图观察场景时,场景中的一个单元对应屏幕上的一个像素。
三个Graphics View基本类有各自不同的坐标系,场景坐标、视图坐标和图元坐标。Graphics View提供了三个坐标系统之间的转换函数。在绘制图形时,Graphics View的场景坐标对应QPainter的逻辑坐标、视图坐标和设备坐标。

  • 场景坐标
    场景坐标是所有图元的基础坐标系统。场景坐标系统描述了顶层的图元,每个图元都有场景坐标和相应的包容框。场景坐标的原点在场景中心,坐标原点是x轴正方形向右,y轴正方向向下。
    QGraphicsScene类的坐标系以中心为原点(0,0)。
    在这里插入图片描述
  • 视图坐标
    视图坐标是窗口部件的坐标。视图坐标的单位是像素。QGraphicsView视图的左上角(0,0),x轴正方向向右,y轴正方向向下。所有的鼠标事件最开始都是使用视图坐标。
    QGraphicsView类继承自QWidget类,因此它与其他的QWidget类一样,以窗口的左上角作为自己坐标系的原点。
    在这里插入图片描述
  • 图元坐标
    图元使用自己的本地坐标,这个坐标系统通常以图元中心为原点,这也是所有变换的原点。图元坐标方向是x轴正方向向右,y轴正方向向下。创建图元后,只需要注意图元坐标即可,QGraphicsScene和QGraphicsView会完成所有的变换。
    QGraphicsItem类的坐标系,若在调用QGraphicsView类的paint()函数重绘图元时,则以此坐标系为基准,如下:
    在这里插入图片描述

根据需要,Qt提供了这三个坐标系之间的互相转换函数,以及图元与图元之间的转换函数,若需要从QGraphicsItem坐标系中的某一点坐标转换到场景中的坐标,则可调用QGraphicsItem的mapToScene()函数进行映射。而QGraphicsItem的mapToParent()函数则可将QGraphicsItem坐标系中的某点坐标映射到它的上一级坐标系中,有可能是场景坐标,也可能是另一个QGraphicsItem坐标。
Graphics View框架提供了多种坐标变换函数。如下:

映射函数转换类型
QGraphicsView::mapToScene视图到场景
QGraphicsView::mapFromScene场景到视图
QGraphicsItem::mapFromScene场景到图元
QGraphicsItem::mapToScene图元到场景
QGraphicsItem::mapToParent子图元到父图元
QGraphicsItem::mapRectFromParent父图元到子图元
QGraphicsItem::mapToItem本图元到其他图元
QGraphicsItem::mapRectFromItem其他图元到本图元

图形视图

同示例介绍如何进行自定义QGraphicsItem,以及如何通过利用定时器来实现QGraphicsItem动画效果。

飞舞的蝴蝶【示例】

设计界面,一个蝴蝶在屏幕上不停地上下飞舞。

  • 新建一个Qt Widgets Application项目,项目名称为“Butterfly”,基类选择“QMainWindow”,类名命名为“mainwindow”,取消“创建界面”复选框。
  • 添加新建类“Butterfly”,基类旋转“QObject”。
  • butterfly.h
#ifndef BUTTERFLY_H
#define BUTTERFLY_H

#include <QObject>
#include <QGraphicsItem>
#include <QPainter>
#include <QGraphicsScene>
#include <QGraphicsView>

class Butterfly : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    explicit Butterfly(QObject *parent = nullptr);
    void timerEvent(QTimerEvent *event);//定时器实现动画的原理是在定时器的timerEvent()中对QGraphicsItem进行重绘
    QRectF boundingRect()const;//为图元限定区域范围,所有继承自QGraphicsItem的自定义图元都必须实现此函数

signals:

public slots:

protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr);//重绘函数

private:
    bool up;
    QPixmap pix_up;
    QPixmap pix_down;
    qreal angle;

};

#endif // BUTTERFLY_H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • butterfly.cpp
#include "butterfly.h"
#include <math.h>
const static double PI = 3.1416;

Butterfly::Butterfly(QObject *parent) : QObject(parent)
{
    up = true;//标志蝴蝶翅膀位置的变量赋初值
    pix_up.load("up.png");//加载图片
    pix_down.load("down.png");
    startTimer(100);
}

QRectF Butterfly::boundingRect() const
{
    qreal adjust = 2;
    return QRectF(-pix_up.width()/2 - adjust, -pix_up.height()/2-adjust, pix_up.width() + adjust*2, pix_up.height() + adjust*2);
}

void Butterfly::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    if(up)
    {
        painter->drawPixmap(boundingRect().topLeft(), pix_up);
        up = !up;
    }
    else{
        painter->drawPixmap(boundingRect().topLeft(), pix_down);
        up = !up;
    }
}

void Butterfly::timerEvent(QTimerEvent *event)
{
    //边界控制
    qreal edgex = scene()->sceneRect().right() + boundingRect().width() / 2;//限定蝴蝶飞舞的右边界
    qreal edgetop = scene()->sceneRect().top() + boundingRect().height() / 2;//限定蝴蝶飞舞的上边界
    qreal edgebottom = scene()->sceneRect().bottom() + boundingRect().height() / 2;//限定蝴蝶飞舞的下边界

    if(pos().x() >= edgex)//超过右边界,水平回到最左边
        setPos(scene()->sceneRect().left(), pos().y());
    if(pos().y() <= edgetop)//超过上边界,回到底边
        setPos(pos().x(), scene()->sceneRect().bottom());
    if(pos().y() >= edgebottom)//超过底边,回到上边界
        setPos(pos().x(), scene()->sceneRect().top());

    angle += (qrand() % 10) / 20.0;
    qreal dx = fabs(sin(angle * PI) * 10.0);
    qreal dy = fabs(qrand()%20) - 10.0;
    setPos(mapToParent(dx, dy));//完成飞行路径。


}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • main.cpp
#include "mainwindow.h"

#include <QApplication>
#include <QGraphicsScene>
#include "butterfly.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsScene *scene = new QGraphicsScene;
    scene->setSceneRect(QRectF(-200, -200, 400, 400));
    Butterfly *butterfly = new Butterfly;
    butterfly->setPos(-100, 0);
    scene->addItem(butterfly);
    QGraphicsView *view = new QGraphicsView;
    view->setScene(scene);
    view->resize(400, 400);
    view->show();

//    MainWindow w;
//    w.show();
    return a.exec();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 执行结果
    在这里插入图片描述

地图浏览器【示例】

实现一个地图浏览器的基本功能,来介绍使用Graphics View框架。

  • 新建Qt Widgets Application,项目名称“MapWidget”,基类选择“QMainWindow”,类名命名为“MainWindow”,取消“创建界面”复选框。
  • 新建类“MapWidget”,继承基类“QGraphicsView”。
  • mapwidget.h
#ifndef MAPWIDGET_H
#define MAPWIDGET_H

#include <QObject>
#include <QGraphicsView>
#include <QMouseEvent>
#include <QLabel>

class MapWidget : public QGraphicsView
{
    Q_OBJECT
public:
    MapWidget();
    void readMap();//读取地图信息
    QPointF mapToMap(QPointF);//用于实现场景坐标系与地图坐标之间的映射,以获得某点的经纬度值。

public slots:
    void slotZoom(int);

protected:
    void drawBackground(QPainter *painter, const QRectF &rect);//完成地图显示功能
    void mouseMoveEvent(QMouseEvent *event);

private:
    QPixmap map;
    qreal zoom;
    QLabel *viewCoord;
    QLabel *sceneCoord;
    QLabel *mapCoord;
    double x1, y1;
    double x2, y2;
};

#endif // MAPWIDGET_H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • mapwidget.cpp
#include "mapwidget.h"
#include <QSlider>
#include <QGridLayout>
#include <QFile>
#include <QTextStream>
#include <QGraphicsScene>
#include <math.h>

MapWidget::MapWidget()
{
    //读取地图信息
    readMap();//用于读取描述地图信息的文件
    zoom = 50;
    int width = map.width();
    int height = map.height();
    QGraphicsScene *scene = new QGraphicsScene(this);//新建一个对象为主窗口连接一个场景
    //限定场景的显示区域为地图的大小
    scene->setSceneRect(-width/2, -height/2, width, height);
    setScene(scene);
    setCacheMode(CacheBackground);
    //用于地图缩放的滑动条
    QSlider *slider = new QSlider;
    slider->setOrientation(Qt::Vertical);
    slider->setRange(1, 100);
    slider->setTickInterval(10);
    slider->setValue(50);
    connect(slider, SIGNAL(valueChanged(int)), this, SLOT(slotZoom(int)));
    QLabel *zoominLabel = new QLabel;
    zoominLabel->setScaledContents(true);
    zoominLabel->setPixmap(QPixmap("zoomin.png"));
    QLabel *zoomoutLabel = new QLabel;
    zoomoutLabel->setScaledContents(true);
    zoomoutLabel->setPixmap(QPixmap("zoomout.png"));
    //坐标值显示区
    QLabel *label1 = new QLabel(tr("GraphicsView:"));
    viewCoord = new QLabel;
    QLabel *label2 = new QLabel(tr("GraphicsScene:"));
    sceneCoord = new QLabel;
    QLabel *label3 = new QLabel(tr("map:"));
    mapCoord = new QLabel;
    //坐标显示区布局
    QGridLayout *gridLayout = new QGridLayout;
    gridLayout->addWidget(label1, 0, 0);
    gridLayout->addWidget(viewCoord, 0, 1);
    gridLayout->addWidget(label2, 1, 0);
    gridLayout->addWidget(sceneCoord, 1, 1);
    gridLayout->addWidget(label3, 2, 0);
    gridLayout->addWidget(mapCoord, 2, 1);
    gridLayout->setSizeConstraint(QLayout::SetFixedSize);
    QFrame *coordFrame = new QFrame;
    coordFrame->setLayout(gridLayout);
    //缩放控制子布局
    QVBoxLayout *zoomLayout = new QVBoxLayout;
    zoomLayout->addWidget(zoominLabel);
    zoomLayout->addWidget(slider);
    zoomLayout->addWidget(zoomoutLabel);
    //坐标显示区域布局
    QVBoxLayout *coordLayout = new QVBoxLayout;
    coordLayout->addWidget(coordFrame);
    coordLayout->addStretch();
    //主布局
    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addLayout(zoomLayout);
    mainLayout->addLayout(coordLayout);
    mainLayout->addStretch();
    mainLayout->setMargin(30);
    mainLayout->setSpacing(10);
    setLayout(mainLayout);
    setWindowTitle(tr("Map Widget"));
    setMinimumSize(600, 400);

}

void MapWidget::readMap()
{
    QString mapName;
    QFile mapFile("maps.text");//新建一个QFile对象, 描述地图信息文本
    int ok = mapFile.open(QIODevice::ReadOnly);//以只读方式打开文件
    if(ok)
    {
        QTextStream ts(&mapFile);
        if(!ts.atEnd())
        {
            ts >> mapName;
            ts >> x1 >> y1 >> x2 >> y2;
        }
    }
    map.load(mapName);//将地图读取到私有变量map中。
}

void MapWidget::slotZoom(int value)
{
    qreal s;
    if(value > zoom)
    {//放大
        s = pow(1.01, (value - zoom));
    }
    else
    {//缩小
        s = pow(1/1.01, (zoom - value));
    }
    scale(s, s);
    zoom = value;
}

void MapWidget::drawBackground(QPainter *painter, const QRectF &rect)
{
    painter->drawPixmap(int(sceneRect().left()), int(sceneRect().top()), map);
}

void MapWidget::mouseMoveEvent(QMouseEvent *event)
{
    //QGraphicsView坐标
    QPoint viewPoint = event->pos();
    viewCoord->setText(QString::number(viewPoint.x()) + "," + QString::number(viewPoint.y()));
    //QGraphicsScene坐标
    QPointF scenePoint = mapToScene(viewPoint);
    sceneCoord->setText(QString::number(scenePoint.x()) + "," + QString::number(scenePoint.y()));
    //地图坐标
    QPointF latLon = mapToMap(scenePoint);
    mapCoord->setText(QString::number(latLon.x()) + "," + QString::number(latLon.y()));
}

QPointF MapWidget::mapToMap(QPointF p)
{
    QPointF latLon;
    qreal w = sceneRect().width();
    qreal h = sceneRect().height();
    qreal lon = y1 - ((h/2 + p.y()) * abs(y1 - y2)/h);
    qreal lat = x1 + ((w/2 + p.x()) + abs(x1 - x2)/w);
    latLon.setX(lat);
    latLon.setY(lon);
    return latLon;
}



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • main.cpp
#include "mainwindow.h"

#include <QApplication>
#include "mapwidget.h"
#include <QFont>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QFont font("ARPL KaitiM GB", 12);
    font.setBold(true);
    a.setFont(font);

    MapWidget mapWidget;
    mapWidget.show();

//    MainWindow w;
//    w.show();
    return a.exec();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 执行结果
    在这里插入图片描述

图元创建【示例】

通过一个示例来演示各个图元的创建。代码结构如下:
在这里插入图片描述具体代码如下:

  • main.cpp
#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QMenuBar>
#include <QGraphicsEllipseItem>
#include "flashitem.h"
#include "startitem.h"

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    //初始化场景
    void initScene();
    //创建主窗体的所有动作
    void createActions();
    //创建主窗体的菜单栏
    void createMenus();

public slots:
    void slotNew();//新建显示窗体
    void slotClear();//清除场景中所有的图元
    void slotAddEllipseItem();//添加一个椭圆形图元
    void slotAddPolygonItem();//添加一个多边形图元
    void slotAddTextItem();         		//在场景中加入一个文字图元
    void slotAddRectItem();         		//在场景中加入一个长方形图元
    void slotAddAlphaItem();        		//在场景中加入一个透明蝴蝶图片
    void slotAddFlashItem();//添加flash图元
    void slotAddAnimationItem();//添加动画图元

private:
    QGraphicsScene *scene;
    QAction *newAct;
    QAction *clearAct;
    QAction *exitAct;
    QAction *addEllipseItemAct;
    QAction *addPolygonItemAct;
    QAction *addTextItemAct;
    QAction *addRectItemAct;
    QAction *addAlphaItemAct;
    QAction *addFlashItemAct;
    QAction *addAnimItemAct;
};
#endif // MAINWINDOW_H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • mainwindow.cpp
#include "mainwindow.h"
#include <QGraphicsItemAnimation>
#include <QTimeLine>
#include <QList>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    //创建主窗体的所有动作
    createActions();
    //创建主窗体的菜单栏
    createMenus();
    scene = new QGraphicsScene;
    scene->setSceneRect(-200, -200, 400, 400);
    //初始化场景
    initScene();
    QGraphicsView *view = new QGraphicsView;
    view->setScene(scene);
    view->setMinimumSize(400, 400);
    view->show();
    setCentralWidget(view);
    resize(550, 450);
    setWindowTitle(tr("Graphics Items"));

}

MainWindow::~MainWindow()
{
}


void MainWindow::createActions()
{
    //创建主窗体的所有动作
    newAct = new QAction(tr("新建"), this);
    clearAct = new QAction(tr("清除"), this);
    exitAct = new QAction(tr("退出"), this);
    addEllipseItemAct = new QAction(tr("加入 椭圆"),this);
    addPolygonItemAct = new QAction(tr("加入 多边形"),this);
    addTextItemAct = new QAction(tr("加入 文字"),this);
    addRectItemAct = new QAction(tr("加入 长方形"),this);
    addAlphaItemAct = new QAction(tr("加入 图片"),this);

    connect(newAct,SIGNAL(triggered()),this,SLOT(slotNew()));
    connect(clearAct,SIGNAL(triggered()),this,SLOT(slotClear()));
    connect(exitAct,SIGNAL(triggered()),this,SLOT(close()));
    connect(addEllipseItemAct,SIGNAL(triggered()),this,SLOT (slotAddEllipseItem()));
    connect(addPolygonItemAct,SIGNAL(triggered()),this,SLOT (slotAddPolygonItem()));
    connect(addTextItemAct,SIGNAL(triggered()),this,SLOT (slotAddTextItem()));
    connect(addRectItemAct,SIGNAL(triggered()),this,SLOT (slotAddRectItem()));
    connect(addAlphaItemAct,SIGNAL(triggered()),this,SLOT (slotAddAlphaItem()));


    addFlashItemAct = new QAction(tr("加入闪烁圆"),this);
    connect(addFlashItemAct,SIGNAL(triggered()),this,SLOT(slotAddFlashItem()));
    addAnimItemAct = new QAction(tr("加入 移动星星"),this);
    connect(addAnimItemAct,SIGNAL(triggered()),this,SLOT(slotAddAnimationItem()));

}

void MainWindow::createMenus()
{
    QMenu *fileMenu = menuBar()->addMenu(tr("文件"));
    fileMenu->addAction(newAct);
    fileMenu->addAction(clearAct);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);
    QMenu *itemMenu = menuBar()->addMenu(tr("元素"));
    itemMenu->addAction(addEllipseItemAct);
    itemMenu->addAction(addPolygonItemAct);
    itemMenu->addAction(addTextItemAct);
    itemMenu->addAction(addRectItemAct);
    itemMenu->addAction(addAlphaItemAct);
    itemMenu->addAction(addFlashItemAct);
    itemMenu->addAction(addAnimItemAct);
}

void MainWindow::initScene()
{
    //初始化场景
    for(int i = 0; i < 3; i++)
        slotAddEllipseItem();
    for(int i = 0; i < 3; i++)
        slotAddPolygonItem();
    for(int i = 0; i < 3; i++)
        slotAddTextItem();
    for(int i = 0; i < 3; i++)
        slotAddRectItem();
    for(int i = 0; i < 3; i++)
        slotAddAlphaItem();
    for(int i = 0; i < 3; i++)
        slotAddFlashItem();
    for(int i = 0; i < 3; i++)
        slotAddAnimationItem();
}

void MainWindow::slotNew()
{
    //新建一个显示窗体
    slotClear();
    initScene();
    MainWindow *newWin = new MainWindow;
    newWin->show();
}

void MainWindow::slotClear()
{
    //清除场景中的所有图元
    QList<QGraphicsItem*> listItem = scene->items();
    while(!listItem.empty())
    {
        scene->removeItem(listItem.at(0));
        listItem.removeAt(0);
    }
}

void MainWindow::slotAddEllipseItem()
{
    //在场景中加入椭圆形图元
    QGraphicsEllipseItem *item = new QGraphicsEllipseItem(QRectF(0, 0, 80, 60));
    item->setPen(Qt::NoPen);
    item->setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
    item->setFlag(QGraphicsItem::ItemIsMovable);
    scene->addItem(item);
    item->setPos((qrand() % int(scene->sceneRect().width())) - 200, (qrand() % int(scene->sceneRect().height())) - 200);
}

void MainWindow::slotAddPolygonItem()
{
    QVector<QPoint> v;
    v << QPoint(30, -15) << QPoint(0, -30) << QPoint(-30, -15) << QPoint(-30, 15) << QPoint(0, 30) << QPoint(30, 15);
    QGraphicsPolygonItem *item = new QGraphicsPolygonItem(QPolygonF(v));
    item->setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
    item->setFlag(QGraphicsItem::ItemIsMovable);
    scene->addItem(item);
    item->setPos((qrand() % int(scene->sceneRect().width())) - 200, (qrand() % int(scene->sceneRect().height())) - 200);
}

void MainWindow::slotAddTextItem()
{
    //在场景中添加一个文字图元
    QFont font("Times", 16);
    QGraphicsTextItem *item = new QGraphicsTextItem("Hello Qt!");
    item->setFont(font);
    item->setFlag(QGraphicsItem::ItemIsMovable);
    item->setDefaultTextColor(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
    scene->addItem(item);
    item->setPos((qrand() % int(scene->sceneRect().width())) - 200, (qrand() % int(scene->sceneRect().height())) - 200);
}

void MainWindow::slotAddRectItem()
{
    //添加长方形图元
    QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 60, 60));
    QPen pen;
    pen.setColor(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
    item->setPen(pen);
    item->setBrush(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
    item->setFlag(QGraphicsItem::ItemIsMovable);
    scene->addItem(item);
    item->setPos((qrand() % int(scene->sceneRect().width())) - 200, (qrand() % int(scene->sceneRect().height())) - 200);
}

void MainWindow::slotAddAlphaItem()
{
    //添加一个透明蝴蝶图片
    QGraphicsPixmapItem *item = scene->addPixmap(QPixmap("image.png"));
    item->setFlag(QGraphicsItem::ItemIsMovable);
    item->setPos((qrand() % int(scene->sceneRect().width())) - 200, (qrand() % int(scene->sceneRect().height())) - 200);
}

void MainWindow::slotAddFlashItem()
{
    //添加闪烁图元
    FlashItem *item = new FlashItem;
    scene->addItem(item);
    item->setPos((qrand() % int(scene->sceneRect().width())) - 200, (qrand() % int(scene->sceneRect().height())) - 200);
}

void MainWindow::slotAddAnimationItem()
{
    //添加动画星星
    StartItem *item = new StartItem;
    QGraphicsItemAnimation *anim = new QGraphicsItemAnimation;
    anim->setItem(item);
    QTimeLine *timeLine = new QTimeLine(4000);
    timeLine->setCurveShape(QTimeLine::SineCurve);
    timeLine->setLoopCount(0);
    anim->setTimeLine(timeLine);
    int y = (qrand() % 400) - 200;
    for(int i = 0; i < 400; i++)
    {
        anim->setPosAt(i/400.0, QPointF(i-200, y));
    }
    timeLine->start();
    scene->addItem(item);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • startitem.h
#ifndef STARTITEM_H
#define STARTITEM_H

#include <QGraphicsItem>
#include <QPainter>

class StartItem : public QGraphicsItem
{
public:
    StartItem();
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr);

private:
    QPixmap pix;
};

#endif // STARTITEM_H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • startitem.cpp
#include "startitem.h"

StartItem::StartItem()
{
    pix.load("start.png");
}

QRectF StartItem::boundingRect() const
{
    return QRectF(-pix.width()/2, -pix.height()/2, pix.width(), pix.height());
}

void StartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->drawPixmap(boundingRect().topLeft(), pix);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • flashitem.h
#ifndef FLASHITEM_H
#define FLASHITEM_H

#include <QObject>
#include <QGraphicsItem>
#include <QPainter>
#include <QTimer>

class FlashItem : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    explicit FlashItem(QObject *parent = 0);
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr);
    void timerEvent(QTimerEvent *event);

private:
    bool flash;
    QTimer *timer;
};

#endif // FLASHITEM_H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • flashitem.cpp
#include "flashitem.h"

FlashItem::FlashItem(QObject *parent)
{
    flash = true;//为颜色切换标识。
    setFlag(ItemIsMovable);
    startTimer(1000);//启动定时器
}

QRectF FlashItem::boundingRect() const
{
    qreal adjust = 2;
    return QRectF(-10-adjust, -10-adjust, 43 + adjust, 43 + adjust);
}

void FlashItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->setPen(Qt::NoPen);
    painter->setBrush(Qt::darkGray);//深灰色
    painter->drawEllipse(-7, -7, 40, 40);
    painter->setPen(QPen(Qt::black, 0));
    //闪烁区边线为黑色
    painter->setBrush(flash ? (Qt::red) : (Qt::yellow));
    painter->drawEllipse(-10, -10, 40, 40);
}

void FlashItem::timerEvent(QTimerEvent *event)
{
    flash = !flash;
    update();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 执行效果:
    在这里插入图片描述

图元的旋转、缩放、切变和位移【示例】

通过实现一个示例演示将图元进行旋转、缩放、切变和位移

  • main.cpp
#include "mainwidget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWidget w;
    w.show();

    return a.exec();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • mainwidget.h
#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include <QWidget>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QFrame>
#include "pixitem.h"
class MainWidget : public QWidget
{
    Q_OBJECT

public:
    MainWidget(QWidget *parent = 0);
    ~MainWidget();
    void createControlFrame();
private:
    int angle;
    qreal scaleValue;
    qreal shearValue;
    qreal translateValue;
    QGraphicsView *view;
    QFrame *ctrlFrame;
    PixItem *pixItem;
public slots:
    void slotRotate(int);
    void slotScale(int);
    void slotShear(int);
    void slotTranslate(int);
};

#endif // MAINWIDGET_H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • mainwidget.cpp
#include "mainwidget.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSlider>
#include <QGroupBox>
#include <math.h>
MainWidget::MainWidget(QWidget *parent)
    : QWidget(parent)
{
    angle = 0;
    scaleValue = 5;
    shearValue = 5;
    translateValue = 50;
    QGraphicsScene *scene = new QGraphicsScene;
    //限定新建QGraphicsScene对象的显示区域
    scene->setSceneRect(-200,-200,400,400);
    QPixmap *pixmap = new  QPixmap("image.png");
    pixItem = new PixItem(pixmap);
    scene->addItem(pixItem);
    pixItem->setPos(0,0);
    view = new QGraphicsView;			//新建一个视图对象
    view->setScene(scene);				//将视图对象与场景相连
    view->setMinimumSize(400,400);		//设置视图的最小尺寸为(400,400)
    ctrlFrame = new QFrame;
    createControlFrame();				//新建主窗体右侧的控制面板区
    //主窗口布局
    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->setMargin(10);
    mainLayout->setSpacing(20);
    mainLayout->addWidget(view);
    mainLayout->addWidget(ctrlFrame);
    setLayout(mainLayout);
    setWindowTitle(tr("Graphics Item Transformation"));//设置主窗体的标题
}

void MainWidget::createControlFrame()
{
    //旋转控制
    QSlider *rotateSlider = new QSlider;
    rotateSlider->setOrientation(Qt::Horizontal);
    rotateSlider->setRange(0,360);
    QHBoxLayout *rotateLayout = new QHBoxLayout;
    rotateLayout->addWidget(rotateSlider);
    QGroupBox *rotateGroup = new QGroupBox(tr("Rotate"));
    rotateGroup->setLayout(rotateLayout);
    //缩放控制
    QSlider *scaleSlider = new QSlider;
    scaleSlider->setOrientation(Qt::Horizontal);
    scaleSlider->setRange(0,2*scaleValue);
    scaleSlider->setValue(scaleValue);
    QHBoxLayout *scaleLayout = new QHBoxLayout;
    scaleLayout->addWidget(scaleSlider);
    QGroupBox *scaleGroup = new QGroupBox(tr("Scale"));
    scaleGroup->setLayout(scaleLayout);
    //切变控制
    QSlider *shearSlider = new QSlider;
    shearSlider->setOrientation(Qt::Horizontal);
    shearSlider->setRange(0,2*shearValue);
    shearSlider->setValue(shearValue);
    QHBoxLayout *shearLayout = new QHBoxLayout;
    shearLayout->addWidget(shearSlider);
    QGroupBox *shearGroup = new QGroupBox(tr("Shear"));
    shearGroup->setLayout(shearLayout);
    //位移控制
    QSlider *translateSlider = new QSlider;
    translateSlider->setOrientation(Qt::Horizontal);
    translateSlider->setRange(0,2*translateValue);
    translateSlider->setValue(translateValue);
    QHBoxLayout *translateLayout = new QHBoxLayout;
    translateLayout->addWidget(translateSlider);
    QGroupBox *translateGroup = new QGroupBox(tr("Translate"));
    translateGroup->setLayout(translateLayout);
    connect(rotateSlider,SIGNAL(valueChanged(int)),this,SLOT(slotRotate(int)));
    connect(scaleSlider,SIGNAL(valueChanged(int)),this,SLOT(slotScale(int)));
    connect(shearSlider,SIGNAL(valueChanged(int)),this,SLOT(slotShear(int)));
    connect(translateSlider,SIGNAL(valueChanged(int)),this,SLOT(slotTranslate(int)));
    //控制面板布局
    QVBoxLayout *frameLayout = new QVBoxLayout;
    frameLayout->setMargin(10);
    frameLayout->setSpacing(20);
    frameLayout->addWidget(rotateGroup);
    frameLayout->addWidget(scaleGroup);
    frameLayout->addWidget(shearGroup);
    frameLayout->addWidget(translateGroup);
    ctrlFrame->setLayout(frameLayout);
}

void MainWidget::slotRotate(int value)
{
    view->rotate(value-angle);
    angle = value;
}

void MainWidget::slotScale(int value)
{
    qreal s;
    if(value>scaleValue)
        s=pow(1.1,(value-scaleValue));
    else
        s=pow(1/1.1,(scaleValue-value));
    view->scale(s,s);
    scaleValue=value;
}

void MainWidget::slotShear(int value)
{
    view->shear((value-shearValue)/10.0,0);
    shearValue=value;
}

void MainWidget::slotTranslate(int value)
{
    view->translate(value-translateValue,value-translateValue);
    translateValue=value;
}

MainWidget::~MainWidget()
{

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 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);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 执行结果
    在这里插入图片描述
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/138782
推荐阅读
相关标签
  

闽ICP备14008679号