QT Graphics View

1.概述

采用QPainter绘图时需要在绘图设备paintEvent()事件里编写绘图的程序,实现整个绘图过程,这种方法如同使用windows的画图软件在绘图,绘制的是位图,这种方法适合于绘制复杂性不高的固定图形,不能实现图件的选择、编辑、拖放、修改等功能。

Graphics View是一种基于图形项的模型/视图模式,并且每个图形元件是可选择、可拖放和修改的,由3个部分组成,场景、视图、图形项

QT Graphics View_第1张图片 视图、场景、图形项的关系

2.场景

QGraphicsScene类提供绘图场景,场景是不可见的,是一个抽象的管理图形项的容器,可以向场景添加图形项,有以下功能。

  • 提供管理大量图形项的快速接口
  • 将事件传播给每个图形项
  • 管理每个图形项的状态,例如选择状态、焦点状态
  • 管理未经变换的渲染功能,主要用于打印

场景还有背景层和前景层,通常由QBrush实现,也可以通过重写drawBackground()和drawForeground()实现。

3.视图

QGraphicsView提供绘图的视图组件,用于显示场景中的内容,可以为一个场景设置几个视图。

如上图所示:虚线框的部分是一个场景,视图1比场景大,显示场景的全部内容。

缺省情况下:

  • 当视图大于场景时,场景在是视图的中间部分显示,也可以设置视图的Alignment属性控制场景在视图中显示的位置;
  • 当视图小于场景时,视图只能显示场景的一部分内容,但是会自动提供滚动条在整个场景内移动。

视图接收键盘和鼠标输入并转换为场景事件,并进行坐标转换后传送给场景。

4.图形项

QGraphicsItem类是图形项的基类,提供了一些基本的图形项,如绘制矩形QGraphicsRectItem、绘制文字QGraphicsTextItem等

QGraphicsItem支持以下操作:

  • 支持鼠标事件响应,包括鼠标按下、移动、释放、双击,等事件
  • 支持键盘输入,按键事件
  • 支持拖放操作
  • 支持组合,可以是父子项关系组合,也可以是通过QGraphicsItemGroup类进行组合

图形项可以被选中、拖放、组合,若编写信号槽代码,还可以实现各种编辑功能,还支持碰撞检测。

5.Graphics View坐标系统

Graphics View系统有3个坐标系,图形项坐标、场景坐标、视图坐标。

QT Graphics View_第2张图片

  • 场景坐标等价于QPainter的逻辑坐标,一般以场景中心为原点;
  • 视图坐标与设备坐标相同,是物理坐标,缺省以左上角为原点;
  • 图形项坐标是局部逻辑坐标,一般以图件的中心为原点;

窗口坐标=逻辑坐标 比如move()中的参数对应的都是逻辑坐标,画图用的。

视口坐标=设备坐标=物理坐标(一个坐标点对应一个像素,可以这么理解)实际显示器大小

5.1图形项坐标

图形项使用自己的局部坐标,通常以其中心为(0,0),也是各种坐标变换的中心。创建自定义图形项,绘图图形项时只需考虑其局部坐标,QGraphicsScene和QGraphicsView会自动进行坐标转换。

1.一个图形项的位置是其中心点在父坐标系统中的坐标,对于没有父图形项的图形项,其父对象就是场景,图形项的位置就是在场景中的坐标。

2.如果一个图形项还是其他图形项的父项,父项进行坐标变换时,子项也做同样的坐标变换。

5.2视图坐标

视图坐标就是窗口界面的物理坐标,单位是像素。视图坐标只与widget或视口有关,而与观察的场景无关,QGraphicsView视口的左上角坐标总是(0,0)。

所有的鼠标事件、拖放事件的坐标首先是由视图坐标定义的,然后用户需要将这些坐标映射为场景坐标,以便和图形项交互。

5.3场景坐标

场景坐标是所有图形项的基础坐标,场景坐标描述了每个顶层图形项的位置,创建场景时可以定义场景矩形区的坐标范围。

例如 scene = new QGraphicsScene(-400,-300,800,600);这样定义的scene是左上角坐标为((-400,-300),宽度为800,高度为600的矩形区域,单位为像素。

每个图形项在场景里都有一个位置坐标,由函数QGraphicsItem::scenePos()给出;

图形项边界矩形,由QGraphicsItem::sceneBoundingRect()函数给出。边界矩形可以使QGraphicsScene知道场景的哪个区域发生了变化。场景发生变化时会发射QGraphicsScene::changed()信号,参数是一个场景的矩形列表,表示发生变化的矩形区。

5.4坐标映射

在场景中操作图形项时,进行场景到图形项、图形项到图形项,或视图到场景之间的坐标变换时比较有用的,即坐标映射。

例如,在QGraphicsView的视口上单击鼠标时,通过函数QGraphicsView::mapToScene()可以将视图坐标映射为场景坐标,然后用QGraphicsScene::itemAt()函数可以获取场景中鼠标光标处的图形项,

6.Graphics View结构相关的类

6.1视图类QGraphicsView

它是用于观察一个场景的物理窗口,当场景小于视图,整个场景在视图中可见;当场景大于视图,视图自动提供滚动条。

QGraphicsView的视口坐标等于显示设备的物理坐标,但是也可以对QGraphicsView的坐标进行平移、选择、缩放等变换。

以下为常用的方法。

QT Graphics View_第3张图片

6.2场景类QGraphicsScene

QGraphicsScene是用于管理图形项的场景,是图形项的容器,有添加、删除图形项的函数。

以下为常用的方法。

QT Graphics View_第4张图片

6.3图形项类QGraphicsItem

QGraphicsItem是所有图形项的基类,用户也可以从QGraphicsItem继承自定义图形项。

以下为常见的图形项的类的继承关系。

QT Graphics View_第5张图片

以下为常用的方法。

QT Graphics View_第6张图片

7.示例

QT Graphics View_第7张图片

7.1自定义MyGraphicsView类

ui界面直接拖放一个QGraphicsView,直接提升为MyGraphicsView。

#ifndef MYGRAPHICSVIEW_H
#define MYGRAPHICSVIEW_H

#include 
#include 
#include 
#include 

class MyGraphicsView : public QGraphicsView
{
    Q_OBJECT
public:
    MyGraphicsView(QWidget *parent = 0);

signals:
    void mouseMovePoint(QPoint point);
    void mouseClicked(QPoint point);

protected:
    void mouseMoveEvent(QMouseEvent *event);
    void mousePressEvent(QMouseEvent *event);
};

#endif // MYGRAPHICSVIEW_H


#include "MyGraphicsView.h"

MyGraphicsView::MyGraphicsView(QWidget *parent)
    :QGraphicsView(parent)
{

}

void MyGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
    QPoint point = event->pos();
    emit mouseMovePoint(point);
    QGraphicsView::mouseMoveEvent(event);
}

void MyGraphicsView::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        QPoint point = event->pos();
        emit mouseClicked(point);
    }
    QGraphicsView::mousePressEvent(event);
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include 
#include 
#include 
#include 

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

private:
    void initGraphicsSystem();

public slots:
    void on_mouseMovePoint(QPoint point);
    void on_mouseClicked(QPoint point);

private:
    QGraphicsScene *m_scene = nullptr;  //场景

    QLabel *m_lbViewCord= nullptr;  //视图坐标
    QLabel *m_lbSceneCord= nullptr; //场景坐标
    QLabel *m_lbItemCord= nullptr;  //图形项坐标
};

#endif // MAINWINDOW_H

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include 

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    m_lbViewCord = new QLabel("View 坐标:");
    m_lbViewCord->setMinimumWidth(150);

    m_lbSceneCord= new QLabel("Scene 坐标:");
    m_lbSceneCord->setMinimumWidth(150);

    m_lbItemCord= new QLabel("Item 坐标:");
    m_lbItemCord->setMinimumWidth(150);

    //添加到状态栏
    ui->statusbar->addWidget(m_lbViewCord);
    ui->statusbar->addWidget(m_lbSceneCord);
    ui->statusbar->addWidget(m_lbItemCord);

    //设置view属性
    ui->graphicsView->setCursor(Qt::CrossCursor);
    ui->graphicsView->setMouseTracking(true);
    ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag);

    connect(ui->graphicsView,&MyGraphicsView::mouseMovePoint,this,
            &MainWindow::on_mouseMovePoint);
    connect(ui->graphicsView,&MyGraphicsView::mouseClicked,this,
            &MainWindow::on_mouseClicked);

    initGraphicsSystem();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::initGraphicsSystem()
{
    QRectF rect(-200,-100,400,200);

    //m_scene逻辑坐标系定义
    m_scene = new QGraphicsScene(rect);

    ui->graphicsView->setScene(m_scene);

    //画一个矩形框,大小等于scene
    QGraphicsRectItem *item = new QGraphicsRectItem(rect);
    item->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);//可选择

    //设置画笔宽
    QPen pen;
    pen.setWidth(2);
    item->setPen(pen);

    m_scene->addItem(item);

    //画一个位于scene中心的椭圆
    QGraphicsEllipseItem *item2 = new QGraphicsEllipseItem(-100,-50,200,100);
    item2->setPos(0,0);
    item2->setBrush(QBrush(Qt::blue));
    item2->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable
                    | QGraphicsItem::ItemIsMovable);    //设置可拖动
    m_scene->addItem(item2);

    //画一个位于scene边缘的椭圆
    QGraphicsEllipseItem *item3 = new QGraphicsEllipseItem(-50,-50,100,100);
    item3->setPos(rect.right(),rect.bottom());
    item3->setBrush(QBrush(Qt::red));
    item3->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable
                    | QGraphicsItem::ItemIsMovable);    //设置可拖动
    m_scene->addItem(item3);

    m_scene->clearSelection();
}

void MainWindow::on_mouseMovePoint(QPoint point)
{
    m_lbViewCord->setText(QString::asprintf("View 坐标:%d,%d",
                                            point.x(),point.y()));
    QPointF pointScene = ui->graphicsView->mapToScene(point);
    m_lbSceneCord->setText(QString::asprintf("Scene 坐标:%.0f,%.0f",
                                             pointScene.x(),pointScene.y()));
}

void MainWindow::on_mouseClicked(QPoint point)
{
    QPointF pointScene = ui->graphicsView->mapToScene(point);
    QGraphicsItem *item = nullptr;
    item = m_scene->itemAt(pointScene,ui->graphicsView->transform());
    if(item)
    {
        QPointF pointItem = item->mapFromScene(pointScene);
        m_lbItemCord->setText(QString::asprintf("Item 坐标:%.0f,%.0f",
                                                pointItem.x(),pointItem.y()));
    }
}

 

你可能感兴趣的:(QGraphicsItem,QGraphicsScene,QGraphicsView,qt,概述)