欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Qt5开发学习之图形视图框架(九)

程序员文章站 2022-03-17 11:09:14
...

图形视图体系结构

Graphics View框架结构主要特点:
1、系统可以利用Qt的反锯齿、OpenGL工具来改善绘图性能。
2、Graphics View支持事件传播体系结构,可以使图元在场景(scene)中的交互能力提升一倍,图元能够处理鼠标事件和键盘事件。
3、在框架中,可以通过二元空间划分树提供快速的图元查找,这样就能实时的显示包含上百万个图元的大场景

Graphics View的三元素:

1、场景类:QGraphicsScene类是一个用于放置图元的容器,本身是不可见的,必须通过与之相连的视图类来显示及与外界进行交互操作。通过QGraphicsScene::addItem()添加一个图元文件到场景中。QGraphicsScene::items()和一些重载函数可以返回各种形状的所有图元。QGraphicsScene::itemAt()返回指定点最顶层的图元。

场景类主要的功能包括:提供对它包含的图元的操作接口和传递事件、管理各个图元的状态(如选择和焦点处理)、提供无变换的绘制功能(如打印):

事件传播体系结构将场景事件发送给图元,同时也管理图元之间的事件传播。

管理各个图元的状态可以通过QGraphicsScene::setSelectionArea()函数选择图元,选择区域可以使任意形状,使用QPainterPath表示。若要的当前选择的图元列表,则可以使用QGraphicsScene::selectedItems()。设置图元的焦点可以使用QGraphicsScene::setFocus()QGraphicsScene::setFocusItem()函数,获得当前具有焦点的图元使用QGraphicsScene::focusItem()

使用QGraphicsScene::render()函数将场景内容绘制到特定的设备上。


2、视图类:QGraphicsView提供一个可视的窗口用于显示场景中的图元。在同一个场景中可以有多个视图,也可以为相同的数据集提供几种不同的视图。

QGraphicsView是可滚动的窗口部件,可以提供滚动条来浏览大的场景。如果需要使用OpenGL,可以使用QGraphicsView::setViewport()将视图设置为QGLWidget

视图接收鼠标和键盘的输入事件,并将它们翻译为场景事件(将坐标转换为场景的坐标),使用变换矩阵函数QGraphicsView::matrix()可以变换场景的坐标,实现场景的缩放和旋转。QGraphicsView::mapToScene()QGraphicsView::mapFromScene()用于与场景的坐标进行互相转换。


3、图元类:QGraphicsItem是场景中各个图元的基类,在它的基础上可以继承出各种图元类。

图元类主要的功能有:

  • 处理鼠标的各种事件;
  • 处理键盘输入事件;
  • 处理拖曳事件;
  • 分组;
  • 碰撞检测;

图元也有自己的坐标系,也提供场景和图元,还可以包含子图元。


GraphicsView的坐标系统

三个GraphicsView基本类有各自不同的坐标系,场景坐标、视图坐标和图元坐标。在绘制图形时,GraphicsView的场景坐标对应QPainter的逻辑坐标、视图坐标和设备坐标。

场景坐标是所有图元的基础坐标系统,描述了顶层的图元,没个图元都有场景坐标和相应的包容框;

视图坐标是窗口部件的坐标,单位是像素。以窗口左上角作为坐标系的原点。

图元坐标使用自己的本地坐标,这个坐标系统通常以图元中心为原点,这也是所有变换的原点。


图形视图

实例:制作动画

首先制作一个图元,通过定时器不停改变图元的显示。再将图元加载到场景中:
图元的制作:

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

class Butterfly : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    explicit Butterfly(QObject *parent = 0);

    // 在定时器函数timerEvent()对QGraphicsItem进行重绘,实现动画
    void timerEvent(QTimerEvent *event);
    // 图元限定区域范围,所有继承自QGraphicsItem的自定义图元都要实现此函数
    QRectF boundingRect() const;

signals:

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

private:
    bool up; // 用于标志蝴蝶翅膀的位置,实现动画
    QPixmap pix_up;
    QPixmap pix_down;
    qreal angle;
};

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);
}

void Butterfly::timerEvent(QTimerEvent *)
{
    // 边界控制
    // 限定蝴蝶的右边界
    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());
    }

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

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;
    }
}

主函数中加载场景:

“`cpp

include

include “Butterfly.h”

include

// 完成了图元的设计,将它加载进场景中
int main(int argc, char *argv[])
{
QApplication a(argc, argv);

QGraphicsScene *scene = new QGraphicsScene;
scene->setSceneRect(-100, -100, 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();

return a.exec();

}