• Qt5开发从入门到精通——第七篇三节( 图形视图—— 图元创建 GraphicsItem V1.0)


    欢迎小伙伴的点评✨✨,相互学习、互关必回、全天在线🍳🍳🍳
    博主🧑🧑 本着开源的精神交流Qt开发的经验、将持续更新续章,为社区贡献博主自身的开源精神👩‍🚀


    前言

    `本章节会给大家带来Graphics View 框架结构的主要特点、 三元素及坐标系统、图元创建。


    一、图形视图体系结构概述

    1.1、Graphics View 框架结构的主要特点

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

    1.2、Graphics View 框架结构的三元素

    Graphics View 框架结构主要包含 三 个类,即场景 类 (QGraphicsScene) 、视图类CQGraphicsView) 和图元类 (QGraphicsltem), 统称为“ 三元素” 。 其中,场景类提供了 一个用于管理位于其中的众多图元容器,视图类用于显示场景中的图元, 一个场景可以通过多个视图表现, 一个场景包括多个几何图形。

    1. 场景类: QGraphicsScene 类
      它是一个用于放置图元的容器,本身是不可见的,必须通过与之相连的视图类来显示及与外界进行互操作。通过 QGraphicsScene: :addltem()可以添加 一个图元到场景中。图元可以通过多个函数进行检索。 QGraphicsScene: :items()和 一些重载函数可以返回与点、矩形、多边形或向 量路径相交的所有图元。QGraphicsScene: :itemAt()返回指定点的顶层图元。
      场景类主要完成的工作包括提供对它包含的图元的操作接口和传递事件、管理各个图元的状态(如选择和焦点处理)、提供无变换的绘制功能(如打印)等。事件传播体系结构将场景事件发送给图元,同时也管理图元之间的事件传播。如果场景接收了在某一点的鼠标单击事件,场景会将事件传给这一点的图元。
      管理各个图元的状态(如选择和焦点处理)。可以通过 QGraphicsScene::setSelectionArea() 函数选择图元,选择区域可以是任意的形状,使用 QPainterPath 表示。若要得到当前选择的图元列表,则可以使用 QGraphicsScene:: selectedltems()函数。可以通过 QGraphicsScene::setFocusltem()函数或 QGraphicsScene::setFocus() 函数来设置图元的焦点,获得当前具有焦点的图元使用QGraphicsScene: :focusltem()函数。如果需要将场景内容绘制到特定的绘图设备,则可以使用 QGraphicsScene: :render()函数在绘图设备上绘制场景。
    2. 视图类: QGraphicsView 类
      它提供一个可视的窗口,用于显示场景中的图元。在同一个场景中可以有多个视图,也可以为相同的数据集提供几种不同的视图。
      QGraphicsView 是可滚动的窗口部件,可以提供滚动条来浏览大的场景。如果需要使用OpenGL, 则可以使用 QGraphicsView: :setViewport()函数将视图设置为 QGLWidget 。视图接收键盘和鼠标的输入事件,并将它们翻译为场景事件(将坐标转换为场景的坐标)。使用变换矩阵函数 QGraphicsView: :matrix()可以变换场景的坐标,实现场景缩放和旋转。QGraphicsView 提供 QGraphicsView::mapToScene()和 QGraphicsView: :mapFromScene()函数用于与场景的坐标进行转换。
    3. 图元类: QGraphicsltem 类
      它是场景中各个图元的基类,在它的基础上可以继承出各种图元类, Qt 已经预置的包括直线 (QGraphicsLineltem) 、椭圆 (QGraphicsEllipseltem) 、文本图元 (QGraphicsTextltem) 、矩形(QGraphicsRectltem) 等。当然,也可以在 QGraphicsltem 类的基础上实现自定义的图元类,即用户可以继承 QGraphicsltem 实现符合自己需要的图元。
      QGraphicsltem 主要有以下功能。
    • 处理鼠标按下、移动、释放、双击、悬停、滚轮和右键菜单事件。
    • 处理键盘输入事件。
    • 处理拖曳事件。
    • 分组。
    • 碰撞检测。
      此外,图元有自己的坐标系统,也提供场景和图元。图元还可以通过 QGraphicsltem:: matrix()函数来进行自身的交换,可以包含子图元。

    1.3、Graphics View框架结构的坐标系统

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

    1. 场景坐标
      场景坐标是所有图元的基础坐标系统。场景坐标系统描述了顶层的图元,每个图元都有场景坐标和相应的包容框。场景坐标的原点在场景中心,坐标原点是 x 轴正方向向右, y 轴正方向向下。QGraphicsScene 类的坐标系以中心为原点 (0,0)。
    2. 视图坐标
      视图坐标是窗口部件的坐标。视图坐标的单位是像素。 QGraphicsView 视图的左上角是(0,0), X 轴正方向向右, y 轴正方向向下。所有的鼠标事件最开始都是使用视图坐标。
      QGraphicsView 类继承自 QWidget 类因此它与其他的 QWidget 类一样,以窗口的左上角作为自己坐标系的原点。
    3. 图元坐标
      图元使用自己的本地坐标,这个坐标系统通常以图元中心为原点,这也是所有变换的原点。图元坐标方向是 x 轴正方向向右, y 轴正方向向下。创建图元后,只需注意图元坐标就可以了,QGraphicsScene 和 QGraphicsView 会完成所有的变换。

    二、GraphicsItem V1.0图元创建效果实例

    图一
    在这里插入图片描述


    三、GraphicsItem V1.0 原码解析

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include 
    #include 
    #include 
    #include 
    #include 
    
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
        void initScene();         //初始化场景
        void createActions();     //创建主窗体的所有动作
        void createMenus();       //创建主窗体的菜单栏
    public slots:
        void slotNew();           //新建一个显示窗体
        void slotClear ();        //清除场景中所有的图元
        void slotAddEllipseItem();  //在场景中加入一个椭圆形图元
        void slotAddPolygonItem (); //在场景中加入一个多边形图元
        void slotAddTextItem();     //在场景中加入一个文字图元
        void slotAddRectItem ();    //在场景中加入一个长方形图元
        void slotAddAlphaItem();   //在场景中加入一个透明蝴蝶图片
    private:
        QGraphicsScene *scene;
        QAction *newAct;
        QAction *clearAct;
        QAction *exitAct;
        QAction *addEllipseItemAct;
        QAction *addPolygonItemAct;
        QAction *addTextItemAct;
        QAction *addRectItemAct;
        QAction *addAlphaItemAct;
    
    };
    
    #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

    main.cpp

    #include "mainwindow.h"
    #include 
    
    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.cpp

    #include "mainwindow.h"
    
    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()));
    }
    
    
    void MainWindow::createMenus()    //创建主窗体的菜单栏
    {
    
        QMenu *fileMenu = menuBar () ->addMenu (tr(" 文件")) ;
        fileMenu->addAction(newAct);
        fileMenu->addAction(clearAct);
        fileMenu->addSeparator();
        fileMenu->addAction(exitAct);
        QMenu *itemsMenu = menuBar()->addMenu(tr(" 元素")) ;
        itemsMenu->addAction(addEllipseItemAct);
        itemsMenu->addAction(addPolygonItemAct);
        itemsMenu->addAction(addTextItemAct);
        itemsMenu->addAction(addRectItemAct);
        itemsMenu->addAction(addAlphaItemAct);
    }
    
    
    void MainWindow:: initScene ()     //初始化场景
    {
        int i;
        for(i=0;i<3;i++)
        slotAddEllipseItem ();
        for(i=0;i<3;i++)
        slotAddPolygonItem();
        for(i=0;i<3;i++)
        slotAddTextItem () ;
        for(i=0;i<3;i++)
        slotAddRectItem();
        for(i=0;i<3;i++)
        slotAddAlphaItem();
    }
    
    
    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.setWidth(3);
        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(":/src/piKa.png"));
        item->setFlag(QGraphicsItem::ItemIsMovable);
        item->setPos ((qrand ()%int (scene->sceneRect ().width())) -200,
        (qrand() %int (scene->sceneRect () . height())) -200) ;
    }
    
    
    • 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

    四、总结

    图元创建会在应用程序开发中经常用到的

  • 相关阅读:
    分享两个小技巧,让你的PPT看起来更高级
    微信小程序入门
    HTTPS请求阶段图解分析
    请求一下子太多了,数据库危
    arm-none-eabi-gcc下实现printf的两种方式
    关于图形学中生成三角形库Triangle.Net的下载及简单使用
    《数据资产管理实践白皮书》5.0版--数据资产管理保障措施
    C++多态学习笔记
    【牛客网面试必刷TOP101】二分查找/排序
    国标GB28181协议客户端开发(三)查询和实时视频画面
  • 原文地址:https://blog.csdn.net/weixin_44759598/article/details/126912719