采用QPainter绘图时需要在绘图设备paintEvent()事件里编写绘图的程序,实现整个绘图过程,这种方法如同使用windows的画图软件在绘图,绘制的是位图,这种方法适合于绘制复杂性不高的固定图形,不能实现图件的选择、编辑、拖放、修改等功能。
Graphics View是一种基于图形项的模型/视图模式,并且每个图形元件是可选择、可拖放和修改的,由3个部分组成,场景、视图、图形项
QGraphicsScene类提供绘图场景,场景是不可见的,是一个抽象的管理图形项的容器,可以向场景添加图形项,有以下功能。
场景还有背景层和前景层,通常由QBrush实现,也可以通过重写drawBackground()和drawForeground()实现。
QGraphicsView提供绘图的视图组件,用于显示场景中的内容,可以为一个场景设置几个视图。
如上图所示:虚线框的部分是一个场景,视图1比场景大,显示场景的全部内容。
缺省情况下:
视图接收键盘和鼠标输入并转换为场景事件,并进行坐标转换后传送给场景。
QGraphicsItem类是图形项的基类,提供了一些基本的图形项,如绘制矩形QGraphicsRectItem、绘制文字QGraphicsTextItem等
QGraphicsItem支持以下操作:
图形项可以被选中、拖放、组合,若编写信号槽代码,还可以实现各种编辑功能,还支持碰撞检测。
Graphics View系统有3个坐标系,图形项坐标、场景坐标、视图坐标。
窗口坐标=逻辑坐标 比如move()中的参数对应的都是逻辑坐标,画图用的。
视口坐标=设备坐标=物理坐标(一个坐标点对应一个像素,可以这么理解)实际显示器大小
图形项使用自己的局部坐标,通常以其中心为(0,0),也是各种坐标变换的中心。创建自定义图形项,绘图图形项时只需考虑其局部坐标,QGraphicsScene和QGraphicsView会自动进行坐标转换。
1.一个图形项的位置是其中心点在父坐标系统中的坐标,对于没有父图形项的图形项,其父对象就是场景,图形项的位置就是在场景中的坐标。
2.如果一个图形项还是其他图形项的父项,父项进行坐标变换时,子项也做同样的坐标变换。
视图坐标就是窗口界面的物理坐标,单位是像素。视图坐标只与widget或视口有关,而与观察的场景无关,QGraphicsView视口的左上角坐标总是(0,0)。
所有的鼠标事件、拖放事件的坐标首先是由视图坐标定义的,然后用户需要将这些坐标映射为场景坐标,以便和图形项交互。
场景坐标是所有图形项的基础坐标,场景坐标描述了每个顶层图形项的位置,创建场景时可以定义场景矩形区的坐标范围。
例如 scene = new QGraphicsScene(-400,-300,800,600);这样定义的scene是左上角坐标为((-400,-300),宽度为800,高度为600的矩形区域,单位为像素。
每个图形项在场景里都有一个位置坐标,由函数QGraphicsItem::scenePos()给出;
图形项边界矩形,由QGraphicsItem::sceneBoundingRect()函数给出。边界矩形可以使QGraphicsScene知道场景的哪个区域发生了变化。场景发生变化时会发射QGraphicsScene::changed()信号,参数是一个场景的矩形列表,表示发生变化的矩形区。
在场景中操作图形项时,进行场景到图形项、图形项到图形项,或视图到场景之间的坐标变换时比较有用的,即坐标映射。
例如,在QGraphicsView的视口上单击鼠标时,通过函数QGraphicsView::mapToScene()可以将视图坐标映射为场景坐标,然后用QGraphicsScene::itemAt()函数可以获取场景中鼠标光标处的图形项,
它是用于观察一个场景的物理窗口,当场景小于视图,整个场景在视图中可见;当场景大于视图,视图自动提供滚动条。
QGraphicsView的视口坐标等于显示设备的物理坐标,但是也可以对QGraphicsView的坐标进行平移、选择、缩放等变换。
以下为常用的方法。
QGraphicsScene是用于管理图形项的场景,是图形项的容器,有添加、删除图形项的函数。
以下为常用的方法。
QGraphicsItem是所有图形项的基类,用户也可以从QGraphicsItem继承自定义图形项。
以下为常见的图形项的类的继承关系。
以下为常用的方法。
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()));
}
}