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

  • 17
    点赞
  • 129
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
Qt QGraphicsView是一个强大的图形界面框架,可以让用户轻松地在图形视图中显示和编辑图形元素。在Qt中,QGraphicsItemQGraphicsScene中的基本元素,它可以表示任何类型的图形图元,如线条、多边形、文本、图像等。在本文中,我们将介绍如何使用Qt QGraphicsView创建自定义图元。 1. 创建自定义图元类 首先,我们需要创建一个自定义图元类,继承自QGraphicsItem。这个类可以是任何自定义的图形元素,比如矩形、圆形、多边形等。在这里,我们将创建一个简单的矩形图元类。 class MyRectItem : public QGraphicsItem { public: MyRectItem(QGraphicsItem *parent = nullptr); QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; }; 2. 实现boundingRect和paint函数 在自定义图元类中,我们需要实现boundingRect和paint函数。boundingRect函数返回一个QRectF对象,用于定义图元的边界框。paint函数用于绘制图元。 QRectF MyRectItem::boundingRect() const { return QRectF(-50, -50, 100, 100); } void MyRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) Q_UNUSED(widget) painter->setPen(QPen(Qt::black, 2)); painter->setBrush(QColor(255, 0, 0, 50)); painter->drawRect(-50, -50, 100, 100); } 3. 在场景中添加图元 在主程序中,我们可以创建一个QGraphicsScene对象,并在其中添加自定义的图元对象。然后,我们可以使用QGraphicsView来显示这个场景QGraphicsScene *scene = new QGraphicsScene; MyRectItem *rectItem = new MyRectItem; scene->addItem(rectItem); QGraphicsView *view = new QGraphicsView(scene); view->show(); 4. 运行程序 现在,我们可以运行程序,并看到我们刚刚创建的矩形图元。可以通过移动、缩放、旋转等操作来编辑图元。 通过这个简单的例子,我们可以看到如何使用Qt QGraphicsView创建自定义图元。可以扩展这个例子来创建更复杂的图元,比如多边形、文本、图像等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wb175208

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值