QGraphicsView移动图元/场景以及坐标转换
使用Qt来画图的时候,需要了解一下QGraphicsView(视图)、QGraphicsScene(场景)、QGraphicsItem(图元),已经他们之间的关系。通过把各种 图元(基类都是:QGraphicsItem)组合在一起搭建成场景(QGraphicsScene),把搭建好的场景通过视图展示出来(QGraphicsView)。通过一个示例来展示,选中图元的时候可以移动图元,选中空白的时..
使用Qt来画图的时候,需要了解一下QGraphicsView(视图)、QGraphicsScene(场景)、QGraphicsItem(图元),已经他们之间的关系。
通过把各种 图元(基类都是:QGraphicsItem)组合在一起搭建成场景(QGraphicsScene),把搭建好的场景通过视图展示出来(QGraphicsView)。
通过一个示例来展示,选中图元的时候可以移动图元,选中空白的时候可以移动整个场景:
1.坐标转换
这三者之间的存在不同的坐标系,他们之间需要坐标转换,而且只用QGraphicsItem和QGraphicsView有坐标转换的功能,也就是说QGraphicsItem和QGraphicsView都可以QGraphicsScene直接进行坐标转换,但是QGraphicsItem和QGraphicsView之间的坐标转换需要通过QGraphicsScene进行转换。
所有的图元QGraphicsItem都是放到QGraphicsScene中,所以QGraphicsScene是所有的图元的父图元。
常用的坐标转换函数:
QGraphicsView::mapToScene() - 视图 -> 场景
QGraphicsView::mapFromScene() - 场景 -> 视图
QGraphicsItem::mapFromScene() - 场景 -> 图元
QGraphicsItem::mapToScene() - 图元 -> 场景
QGraphicsItem::mapToParent() - 子图元 -> 父图元
QGraphicsItem::mapFromParent() - 父图元 -> 子图元
QGraphicsItem::mapToItem() - 本图元 -> 其他图元
QGraphicsItem::mapFromItem() - 其他图元 -> 本图元
2.图元/场景移动
如果是移动单个图元的话,
setFlag(QGraphicsItem::ItemIsMovable, true);//可以拖动
setFlag(QGraphicsItem::ItemIsSelectable, true);//可以选中
贴上代码:
自定义图元:
#pragma once
#include <QGraphicsEllipseItem>
class IGraphicsCoord;
class AAAEllipseItem : public QGraphicsEllipseItem {
public:
AAAEllipseItem(QGraphicsItem *parent);
~AAAEllipseItem();
inline void setCoord(IGraphicsCoord* coord){
_graphicsCoord = coord;
}
private:
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event)Q_DECL_OVERRIDE;
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event)Q_DECL_OVERRIDE;
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)Q_DECL_OVERRIDE;
private:
IGraphicsCoord* _graphicsCoord = nullptr;
QPointF _mousePress;
};
#include "AAAEllipseItem.h"
#include <QDebug>
#include <QPen>
#include <QGraphicsSceneMouseEvent>
#include "IGraphicsCoord.h"
AAAEllipseItem::AAAEllipseItem(QGraphicsItem *parent)
: QGraphicsEllipseItem(parent) {
setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemIsSelectable, true);
QPen pen;
pen.setColor(QColor(247, 99, 0));
pen.setWidth(3);
setPen(pen);
}
AAAEllipseItem::~AAAEllipseItem() {
}
void AAAEllipseItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
QGraphicsEllipseItem::mousePressEvent(event);
qDebug() << "AAAEllipseItem:" << event->pos().x() << event->pos().y();
QPointF ptScene = mapToScene(event->pos());
qDebug() << "AAAEllipseItem mapToScene:" << ptScene.x() << ptScene.y();
if (_graphicsCoord != nullptr){
_graphicsCoord->itemToSence(ptScene);
}
}
void AAAEllipseItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
QGraphicsEllipseItem::mouseMoveEvent(event);
}
void AAAEllipseItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
QGraphicsEllipseItem::mouseReleaseEvent(event);
}
自定义场景:
#pragma once
#include <QGraphicsScene>
class AAAGraphicsScene : public QGraphicsScene {
Q_OBJECT
public:
AAAGraphicsScene(QObject *parent);
~AAAGraphicsScene();
private:
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event)Q_DECL_OVERRIDE;
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event)Q_DECL_OVERRIDE;
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)Q_DECL_OVERRIDE;
};
#include "AAAGraphicsScene.h"
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
AAAGraphicsScene::AAAGraphicsScene(QObject *parent)
: QGraphicsScene(parent) {
}
AAAGraphicsScene::~AAAGraphicsScene() {
}
void AAAGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) {
QGraphicsScene::mousePressEvent(event);
qDebug() << "AAAGraphicsScene:" << event->pos().x() << event->pos().y();
}
void AAAGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
QGraphicsScene::mouseMoveEvent(event);
}
void AAAGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
QGraphicsScene::mouseReleaseEvent(event);
}
自定义视图:
#pragma once
#include <QGraphicsView>
#include "IGraphicsCoord.h"
class IGraphicsCoord2;
class AAAGraphicsView : public QGraphicsView,public IGraphicsCoord {
Q_OBJECT
public:
AAAGraphicsView(QWidget *parent);
~AAAGraphicsView();
inline void setItemCoord(IGraphicsCoord2* coord){
_graphicsCoord2 = coord;
}
protected:
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
private:
virtual void itemToSence(QPointF pt)override;
private:
IGraphicsCoord2* _graphicsCoord2 = nullptr;
QPoint _mouseLBtnDown;
bool _isLBtnDown = false;
};
#include "AAAGraphicsView.h"
#include <QDebug>
#include <QMouseEvent>
AAAGraphicsView::AAAGraphicsView(QWidget *parent)
: QGraphicsView(parent) {
//隐藏水平/竖直滚动条
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//设置场景范围
setSceneRect(INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX);
//反锯齿
setRenderHints(QPainter::Antialiasing);
}
AAAGraphicsView::~AAAGraphicsView() {
}
void AAAGraphicsView::mousePressEvent(QMouseEvent *event) {
QGraphicsView::mousePressEvent(event);
qDebug() << "AAAGraphicsView:" << event->pos().x() << event->pos().y();
if (event->button() == Qt::LeftButton){
if (scene()->itemAt(mapToScene(event->pos()), transform()) == nullptr) {//没有选中任何图元
qDebug() << QStringLiteral("没有选中图元");
_mouseLBtnDown = event->pos();
_isLBtnDown = true;
}
}
}
void AAAGraphicsView::mouseMoveEvent(QMouseEvent *event) {
QGraphicsView::mouseMoveEvent(event);
if (_isLBtnDown){
QPointF ptNow = mapToScene(event->pos());
QPointF movePt = ptNow - mapToScene(_mouseLBtnDown);
//根据鼠标当前的点作为定位点
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
QPoint nowCenter(-movePt.x(), -movePt.y());
//qDebug() << "nowCenter:" << nowCenter.x()<< " "<< nowCenter.y();
centerOn((nowCenter));
setTransformationAnchor(QGraphicsView::AnchorViewCenter);
}
}
void AAAGraphicsView::mouseReleaseEvent(QMouseEvent *event) {
QGraphicsView::mouseReleaseEvent(event);
if (event->button() == Qt::LeftButton) {
_isLBtnDown = false;
}
}
void AAAGraphicsView::itemToSence(QPointF pt) {
QPointF ptFromScene = mapFromScene(pt);
qDebug() << "AAAGraphicsView mapFromSence:" << ptFromScene.x() << ptFromScene.y();
}
定义接口:
#pragma once
#include <QPointF>
class IGraphicsCoord {
public:
IGraphicsCoord();
~IGraphicsCoord();
virtual void itemToSence(QPointF pt);
};
#include "IGraphicsCoord.h"
IGraphicsCoord::IGraphicsCoord() {
}
IGraphicsCoord::~IGraphicsCoord() {
}
void IGraphicsCoord::itemToSence(QPointF pt) {
}
创建场景:
void QtGuiOPenGL::init3() {
AAAGraphicsScene* scene = new AAAGraphicsScene(this);
AAAEllipseItem* e1 = new AAAEllipseItem(nullptr);
e1->setRect(10, 10, 100, 100);
scene->addItem(e1);
AAAEllipseItem* e2 = new AAAEllipseItem(nullptr);
e2->setRect(20, 20, 200, 100);
scene->addItem(e2);
scene->addLine(0.0, 0.0, 100.0, 0.0);
scene->addLine(0.0, 0.0, 0.0, 100.0);
AAAGraphicsView* view = new AAAGraphicsView(this);
e1->setCoord(view);
//view->setAlignment(Qt::AlignLeft | Qt::AlignTop);
view->setScene(scene);
ui.verticalLayout->addWidget(view) ;
}
运行之后,当点击一个图元的时候,输出的信息:
AAAEllipseItem: 54 43
AAAEllipseItem mapToScene: 54 43
AAAGraphicsScene: 54 43
AAAGraphicsView: 357 304
这也说明了,鼠标事件传递的顺序:
图元-> 场景->视图
QGraphicsItem -> QGraphicsScene -> QGraphicsView
视图和图元的交互是通过场景来装换的。
aaa
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)