基于QGraphicsView、QGraphicsScene、自定义QGraphicsItem的小demo(正矩形、旋转矩形及圆形)

本文档记录了一个Qt图形视图框架的Demo实现,包括以鼠标为中心的缩放、固定大小的背景绘制以及自定义图像项的操作。Demo旨在避免重复编写QGraphicsView和QGraphicsScene,同时添加了正矩形、旋转矩形和圆形图形项,使用工厂模式进行扩展。在图形项上,实现了边缘控制点,这些点不随视图缩放而缩放,并能响应鼠标事件进行图形编辑。此外,详细展示了各个关键代码段的实现细节,如滚轮事件处理、背景绘制、图像Item和自定义图形Item的绘制与交互等。

网上有很多关于这三个的资料,这方面的功能不做过多的描述,仅仅将在做小Demo过程中遇到的问题做下记录,下面是Demo的界面图:

Demo的初衷是不想每次使用QGraphicsView和QGraphicsScene都重写,可以直接拿来使用,后来慢慢加了一些图形项,因为其实是为了熟悉QGpaphicsXX,所以目前只加了3种(正矩形,旋转矩形、圆),刚好这个Demo也练习了一种设计模式——工厂模式,现在就讲些步骤及遇到的问题(只贴关键的代码,整体代码看最后下载链接):

一、以鼠标为中心进行缩放

QGraphicsView和QGraphicsScene(后面简称View和Scene)都是要重写的,这一部分我主要放在View中实现,主要重写滚轮事件 wheelEvent(QWheelEvent * event),代码(部分)如下:

void MyGraphicsView::wheelEvent(QWheelEvent * event)
{
	if (this->scene()->items().size() == 0)
		return;
	QPointF curPoint = event->pos();
	QPointF scenePos = this->mapToScene(QPoint(curPoint.x(), curPoint.y()));

	qreal viewWidth = viewport()->width();
	qreal viewHeight = viewport()->height();

	qreal hScale = curPoint.x() / viewWidth;
	qreal vScale = curPoint.y() / viewHeight;

	int wheelDeltaValue = event->delta();
	// 当前放缩倍数;
	qreal scaleFactor = this->matrix().m11();
	if ((scaleFactor < 0.4 && wheelDeltaValue<0)||(scaleFactor>50 &&wheelDeltaValue>0))
		return;

	wheelDeltaValue > 0 ? scale(1.2, 1.2) : scale(1.0/1.2, 1.0/1.2);
	// 将scene坐标转换为放大缩小后的坐标;
	QPointF viewPoint = this->matrix().map(scenePos);
	this->horizontalScrollBar()->setValue(int(viewPoint.x() - viewWidth * hScale ));
	this->verticalScrollBar()->setValue(int(viewPoint.y() - viewHeight * vScale ));

	update();
}

这段代码其实是通过控制ScrollBar来达到目的,但是其实可以不需要这么做,只需要在构造函数中设置属性即可,构造函数如下:

MyGraphicsView::MyGraphicsView(QWidget *parent)
	: QGraphicsView(parent)
{
	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // 去掉滚动条
	setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
	setRenderHints(QPainter::Antialiasing);

	/*以鼠标中心进行缩放*/
	setMouseTracking(true);        
	setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
	setResizeAnchor(QGraphicsView::AnchorUnderMouse);
	/********************/

}

构造函数中的后三句才是重点。之所以还留着滚轮事件中ScrollBar->setValue()是发现在放大过程中放大到一定程度,加载进去的图片就“消失”。

注:在Scene中要设置SceneRect的大小,尽量大,具体看后面附带的代码下载链接;

二、绘制不随窗口变化大小的背景

Demo带有棋盘格的背景,实现是重写View的drawBackground(QPainter * painter, const QRectF & rect);

void MyGraphicsView::drawBackground(QPainter * painter, const QRectF & rect)
{
	//绘制背景
	int wid = this->geometry().width();
	int hei = this->geometry().height();
	m_ptCenter = this->mapToScene(wid / 2, hei / 2);
	QPixmap pix(wid, hei);
	QPainter pter(&pix);
	QColor clr_white(Qt::white);
	QColor clr_gray(240, 240, 240, 240);
	int spacing = 15;
	QColor useColor;
	for (int i = 0; i <= floor(wid / spacing); i++)
	{
		for (int j = 0; j <= floor(hei/ spacing); j++)
		{
			useColor = ((i + j) % 2 == 0 ? clr_white : clr_gray);
			pter.fillRect(i*spacing, j*spacing, spacing, spacing, useColor);
		}
	}
	painter->drawImage(rect, pix.toImage());
}

三、加载自定义图像Item

自定义图像item其实就是继承QGraphicsItem,由于代码里加了很多图形item,只显示部分;

QRectF MyGraphicsImageItem::boundingRect() const
{
	return QRectF(-m_Pixmap.width() / 2, -m_Pixmap.height() / 2, m_Pixmap.width(), m_Pixmap.height());
}

void MyGraphicsImageItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
	Q_UNUSED(option);
	Q_UNUSED(widget);
	QPen pen = painter->pen();
	pen.setWidth(0);
	pen.setStyle(Qt::SolidLine);
	pen.setColor(QColor(0, 255, 255, 100));
	painter->setPen(pen);
	painter->setBrush(QColor(0, 0, 255, 100));
	painter->drawPixmap(-m_Pixmap.width() / 2, -m_Pixmap.height() / 2, m_Pixmap);
}

四、在图像Item上绘制图形item

1、图形边缘控制点

边缘控制点其实也是自定义的Item,定义为MyCornerItem,该Item不随视图的缩放而缩放,需要更新移动后item的位置:

#pragma once
#ifndef MY_CORNER_ITEM_H
#define MY_CORNER_ITEM_H

#include <QAbstractGraphicsShapeItem>
#include <QGraphicsSceneHoverEvent>
#include <QPainter>
#include <QCursor>
#include <QGraphicsItem>

enum CustomType {
	TypeImage = 65536 + 1,
	TypeCorner = 65536 + 2,
	TypeRect,
	TypeRotateRect,
	TypeCircle
};

constexpr int CORNER_SIZE = 3;

enum SelectionHandleState
{
	SelectionHandleOff,
	SelectionHandleInactive,
	SelectionHandleActive
};

enum CornerDirction    //鼠标经过时的形状
{
	None = 0,
	LeftTop,
	Top,
	RightTop,
	Right,
	RightBottom,
	Bottom,
	LeftBottom,
	Left,
	Rotation,           //旋转
};

class MyCornerItem : public QAbstractGraphicsShapeItem
{
	/*Q_OBJECT*/

public:
	explicit MyCornerItem(QGraphicsItem *parent, QPointF point, CornerDirction dir, bool control = false);
	virtual ~MyCornerItem() {};
	bool hitTest(const QPointF &point);
	CornerDirction getDir() const { return m_Dir; }
	void setState(SelectionHandleState state);
	void move(QPointF point);
	void cornerTranslate(QPointF point);
	inline void setSelectState(bool bState) { m_bSelect = bState; }
	inline bool getSelectState() { return m_bSelect; }
	inline QPointF getPointCenter() { return m_point; }

	virtual int type() const { return TypeCorner; }

private:
	QBrush m_brush;
	QPointF m_point;
	CornerDirction m_Dir;
	SelectionHandleState m_State;
	QCursor m_RotateCursor;  //旋转图标
	double m_scaleFactor;
	bool m_bSelect;   //对由多个点组成的图形,点击被选中的标志
	QPointF m_ptPress, m_ptMove;

protected:
	virtual QRectF boundingRect() const override;
	virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
	virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
	virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) Q_DECL_OVERRIDE;
	virtual void mousePressEvent(QGraphicsSceneMouseEvent* event) override;
	virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;
	virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;


};

#endif
#include "MyCornerItem.h"
#include <QDebug>

MyCornerItem::MyCornerItem(QGraphicsItem * parent, QPointF point, CornerDirction dir, bool control)
	:QAbstractGraphicsShapeItem(parent)
	, m_point(point)
	,m_Dir(dir)
{
	setAcceptHoverEvents(true);
	QPixmap pixRotate = QPixmap("Resources\\icon\\rotate.png");
	m_RotateCursor = QCursor(pixRotate); 
	m_scaleFactor = 1;
	m_bSelect = false;
	m_brush = QBrush(Qt::white);
}

void MyCornerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
	Q_UNUSED(option);     //这个宏是用来把不用到的参数注掉的功能
	Q_UNUSED(widget);
	m_scaleFactor = painter->matrix().m11();
	painter->save();
	QPen pen;
	pen.setWidth(0);
	pen.setStyle(Qt::SolidLine);
	painter->setPen(pen);
	painter->setBrush(m_brush);
	painter->setRenderHint(QPainter::Antialiasing, false);  //不开反走样
	painter->drawEllipse(m_point, CORNER_SIZE/ m_scaleFactor, CORNER_SIZE/ m_scaleFactor);
	painter->restore();
}

bool MyCornerItem::hitTest(const QPointF & point)
{
	//QPointF pt = mapFromScene(point);
	return boundingRect().contains(point);
}

void MyCornerItem::setState(SelectionHandleState state)
{
	if (state == m_State)
		return;
	switch (state) {
	case SelectionHandleOff:
		hide();
		break;
	case SelectionHandleInactive:
	case SelectionHandleActive:
		show();
		break;
	}
	m_State = state;
}

void MyCornerItem::move(QPointF point)
{
	if (point == m_point)
		return;
	//moveBy(0, 0);
	m_point = point;
	update();
}

void MyCornerItem::cornerTranslate(QPointF point)
{
	QPointF local = point + boundingRect().topLeft();
	QRectF delta = QRectF(local, boundingRect().size());
	prepareGeometryChange();
	m_point = delta.center();
	update();
}

QRectF MyCornerItem::boundingRect() const
{
	double centerX = m_point.x() - CORNER_SIZE * 2 / m_scaleFactor / 2;
	double centerY = m_point.y() - CORNER_SIZE * 2 / m_scaleFactor / 2;
	return QRectF(centerX, centerY, CORNER_SIZE * 2 / m_scaleFactor, CORNER_SIZE * 2 / m_scaleFactor);
}

void MyCornerItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
{
	if (event->button() == Qt::LeftButton)
	{
		m_ptPress = event->scenePos();
		m_ptMove = event->scenePos();
		m_bSelect = true;
	}
}

void MyCornerItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
	if (event->buttons()&Qt::LeftButton)
	{
		m_ptMove = event->scenePos();
		QPointF pt = mapFromScene(m_ptMove) - mapFromScene(m_ptPress);
		m_ptPress = event->scenePos();
		cornerTranslate(pt);
	}
	QGraphicsItem::mouseMoveEvent(event);

}

void MyCornerItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
	/*if (event->button() == Qt::LeftButton)
	{
		m_ptMove = event->scenePos();
		QPointF pt = mapFromScene(m_ptMove) - mapFromScene(m_ptPress);
		m_ptPress = event->scenePos();
		cornerTranslate(pt);
	}
	QGraphicsItem::mouseReleaseEvent(event);*/
}

void MyCornerItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
{
	switch (m_Dir)
	{
	case LeftTop:
	case RightBottom:
		setCursor(Qt::SizeFDiagCursor);
		break;
	case LeftBottom:
	case RightTop:
		setCursor(Qt::SizeBDiagCursor);
		break;
	case Top:
	case Bottom:
		setCursor(Qt::SizeVerCursor);
		break;
	case Left:
	case Right:
		setCursor(Qt::SizeHorCursor);
		break;
	case Rotation:
		setCursor(m_RotateCursor);
		break;
	default:
		setCursor(Qt::ArrowCursor);
		break;
	}
	m_brush = QBrush(Qt::green);
	update();
	QGraphicsItem::hoverEnterEvent(event);
}

void MyCornerItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
{
	m_bSelect = false;
	m_brush = QBrush(Qt::white);
	update();
	QGraphicsItem::hoverLeaveEvent(event);
}

2、图形基类及工厂

图形基类继承QGraphicsItem,以组合的方式声明边缘点QList<MyCornerItem*> m_HandlesList,主要实现item移动,左键双击改变z值,右双击可以改变颜色

#ifndef MY_CUSTOMDRAWITEM_H
#define MY_CUSTOMDRAWITEM_H

#include <QGraphicsItem>
#include "MyCornerItem.h"
#include <QPainterPath>
#include <QColorDialog>
#include <QDebug>

/*  需要使用的定义及相关函数  */
constexpr double PI = 3.1415926;

template <typename T>    //T 为QPointF 或QPoint
double Distance(T p1, T p2)
{
	return std::sqrt(std::pow(p1.x() - p2.x(), 2) + std::pow(p1.y() - p2.y(), 2));
}


class QGraphicsItem;
/**图形基类**/
class CustomItemBase : public QGraphicsItem
{
public:
	CustomItemBase(QGraphicsItem *parent = nullptr)
	{
		setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
		this->setAcceptHoverEvents(true);
		m_bUseDoubleClick = true;
		m_brush = QBrush(QColor(0, 0, 255, 100));
	}
	virtual ~CustomItemBase() {};

	void SetState(SelectionHandleState state);
	bool isCornerSelected(int &index);

	void itemAtImage2Move(QPointF point)
	{
		move(point);
	}

	virtual int type() const = 0;
	virtual void move(QPointF point) = 0;  //平移
	virtual void updateShape() = 0;    //拖动corner后要更新形状
	virtual void updateConnerPos() = 0;   //移动后更新所有corner的位置
	virtual QPainterPath shape() const = 0;
protected:
	virtual QRectF boundingRect() const = 0;
	virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value);
	virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) = 0;
	virtual void mousePressEvent(QGraphicsSceneMouseEvent* event) override;
	virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;
	virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
	virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
	
public:
	QRectF m_rect;    //外接矩形
	QList<MyCornerItem*> m_HandlesList;
	QPointF m_ptPress,m_ptMove;
	QBrush m_brush;
	bool m_bUseDoubleClick;
};

class CustomItemBaseFactory
{
public:
	virtual ~CustomItemBaseFactory() {}
	virtual CustomItemBase* CreateCustomItem(QVector<QPointF> vecPoint) = 0;
	virtual void DrawOnPaint(QPainter* painter, QVector<QPointF> vecPoint) = 0;
	virtual int NeedClickCount() 
	{ return --m_nClickCnt; }    //图形需要几步完成

	int m_nClickCnt;
	inline int GetNeedCnt() { return m_nNeedCnt; }

protected:
	int m_nNeedCnt;    //不变
};
#include "MyCustomDrawItem.h"
#include <QGraphicsScene>
#include <QDebug>

/************************************************************************/
/*                图形基类相关函数                                     */
/*    左双击改变Z值,右双击改变颜色                                     */
/************************************************************************/
void CustomItemBase::SetState(SelectionHandleState state)
{
	for (auto item: m_HandlesList)
		item->setState(state);
}

bool CustomItemBase::isCornerSelected(int & index)
{
	bool bSelect = false;
	index = 0;
	for (auto item : m_HandlesList)
	{
		if (item->getSelectState())
		{
			bSelect = true;
			break;
		}
		index++;
	}
	return bSelect;
}

QVariant CustomItemBase::itemChange(GraphicsItemChange change, const QVariant & value)
{
	if (change == QGraphicsItem::ItemSelectedHasChanged)
	{
		qDebug() << "Item Selected:" << value.toString();
		SetState(value.toBool() ? SelectionHandleActive : SelectionHandleOff);
	}
	else if (change == QGraphicsItem::ItemRotationHasChanged)
	{
		qDebug() << "Item Rotation Changed:" << value.toString();
	}
	else if (change == QGraphicsItem::ItemTransformOriginPointHasChanged)
	{
		qDebug() << "ItemTransformOriginPointHasChanged:" << value.toPointF();
	}
	return QGraphicsItem::itemChange(change, value);
}

void CustomItemBase::mousePressEvent(QGraphicsSceneMouseEvent * event)
{
	if (event->button() == Qt::LeftButton)
	{
		m_ptPress = event->scenePos();
		m_ptMove = event->scenePos();
		for (auto corner:m_HandlesList)
		{
			corner->setZValue(this->zValue());
		}
	}
	QGraphicsItem::mousePressEvent(event);
}

void CustomItemBase::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
{
	if (event->buttons() & Qt::LeftButton)
	{
		int index = 0;
		if (!isCornerSelected(index))
		{
			m_ptMove = event->scenePos();
			QPointF pt = mapFromScene(m_ptMove) - mapFromScene(m_ptPress);
			m_ptPress = event->scenePos();
			move(pt);
		}
		update();
	}
}

void CustomItemBase::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
	if (event->button() == Qt::LeftButton)
	{
		for (auto item : m_HandlesList)
		{
			item->setSelectState(false);
		}
		QGraphicsItem::mouseReleaseEvent(event);
	}
}

void CustomItemBase::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)
{
	if (event->button() == Qt::RightButton)
	{
		if (m_bUseDoubleClick)
		{
			QColorDialog dlg;
			if (dlg.exec() == QDialog::Accepted)
			{
				QColor color = dlg.selectedColor();
				color.setAlpha(100);
				m_brush = QBrush(color);
			}
		}
	}
}

至于为什么还要加个“工厂”,主要就是要加入一个图形,如果以switch的方式分别new出相关的类,这样不便于后续添加其他图形,使用工厂模式就解决了该问题。图形有自己的工厂,使用的时候只要传入相应的工厂指针就好了【不知道该模式的话自行补】。下面仅展示正矩形和圆的实现:

/**************矩形******************/
class CustomRectItem :public CustomItemBase
{
public:
	CustomRectItem(QRectF &rect, QGraphicsItem *parent = nullptr);

	virtual int type() const { return TypeRect; }

	virtual void move(QPointF point);
	virtual void updateShape(); //一个corner改变则进行一次更新
	virtual void updateConnerPos();
	virtual QPainterPath shape() const;

protected:
	virtual QRectF boundingRect() const;
	virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

};

class CustomRectItemFactory : public CustomItemBaseFactory
{
public:
	CustomRectItemFactory()
	{
		m_nClickCnt = 1;
		m_nNeedCnt = 1;
	}
	virtual CustomItemBase* CreateCustomItem(QVector<QPointF> vecPoint)
	{
		return new CustomRectItem(QRectF(vecPoint.at(0), vecPoint.at(1)));
	}
	virtual void DrawOnPaint(QPainter* painter, QVector<QPointF> vecPoint)
	{
		painter->drawRect(QRectF(vecPoint.at(0), vecPoint.at(1)));
	}
};

/**************圆**************/
class CustomCircleItem :public CustomItemBase
{
public:
	CustomCircleItem(QPointF center, double radius, QGraphicsItem *parent = nullptr);

	virtual int type() const { return TypeCircle; }

	virtual void move(QPointF point);  //平移
	virtual void updateShape();
	virtual void updateConnerPos();   //移动后更新所有corner的位置
	virtual QPainterPath shape() const;

protected:
	virtual QRectF boundingRect() const;
	virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

};

class CustomCircleItemFactory : public CustomItemBaseFactory
{
public:
	CustomCircleItemFactory()
	{
		m_nClickCnt = 1;
		m_nNeedCnt = 1;
	}
	virtual CustomItemBase* CreateCustomItem(QVector<QPointF> vecPoint)
	{
		double dRadius = Distance(vecPoint.at(0), vecPoint.at(1));
		return new CustomCircleItem(vecPoint.at(0), dRadius);
	}
	virtual void DrawOnPaint(QPainter* painter, QVector<QPointF> vecPoint)
	{
		double radius = Distance(vecPoint.at(0), vecPoint.at(1));
		painter->drawEllipse(vecPoint.at(0), radius, radius);
	}
};
/************************************************************************/
/*    图形子类函数实现                                                  */
 /*   1、 正矩形                                                    */
/************************************************************************/
CustomRectItem::CustomRectItem(QRectF & rect, QGraphicsItem * parent)
{
	m_rect = rect;
	m_HandlesList.clear();
	const int num = 8;
	QPointF point[num] = { QPointF((rect.left() + rect.right()) / 2,rect.bottom()),QPointF(rect.left(),rect.bottom()),
						 QPointF(rect.left(),(rect.top() + rect.bottom()) / 2) ,QPointF(rect.left(),rect.top()),
						 QPointF((rect.left() + rect.right()) / 2,rect.top()),QPointF(rect.right(),rect.top()),
						QPointF(rect.right(),(rect.top() + rect.bottom()) / 2),QPointF(rect.right(),rect.bottom())};
	CornerDirction dir[num] = { Bottom,LeftBottom ,Left,LeftTop ,Top , RightTop, Right,RightBottom };
	for (int i = 0; i < num; i++)
	{
		MyCornerItem* corner = new MyCornerItem(this, point[i], dir[i]);
		m_HandlesList.push_back(corner);
	}
}

void CustomRectItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
{
	Q_UNUSED(option);
	Q_UNUSED(widget);
	QPen pen = painter->pen();
	pen.setWidth(0);
	pen.setColor(QColor(0, 255, 255, 100));
	painter->setPen(pen);
	painter->setBrush(m_brush);

	updateShape();
	painter->drawRect(m_rect);
}

void CustomRectItem::updateShape()
{
	int index = 0;
	if (isCornerSelected(index))
	{
		QRectF rect = m_rect;
		CornerDirction dir = m_HandlesList[index]->getDir();
		switch (dir)
		{
		case Top:
			rect.setTop(m_HandlesList[index]->getPointCenter().y());
			break;
		case Right:
			rect.setRight(m_HandlesList[index]->getPointCenter().x());
			break;
		case Bottom:
			rect.setBottom(m_HandlesList[index]->getPointCenter().y());
			break;
		case Left:
			rect.setLeft(m_HandlesList[index]->getPointCenter().x());
			break;
		case LeftTop:
			rect.setTopLeft(m_HandlesList[index]->getPointCenter());
			break;
		case LeftBottom:
			rect.setBottomLeft(m_HandlesList[index]->getPointCenter());
			break;
		case RightTop:
			rect.setTopRight(m_HandlesList[index]->getPointCenter());
			break;
		case RightBottom:
			rect.setBottomRight(m_HandlesList[index]->getPointCenter());
			break;
		default:
			break;
		}
		prepareGeometryChange();
		m_rect = rect;
		updateConnerPos();
	}
}

QPainterPath CustomRectItem::shape() const
{
	QPainterPath path;
	path.addRect(boundingRect());
	return path;
}

void CustomRectItem::move(QPointF point)
{
	QPointF local = point + m_rect.topLeft();
	QRectF delta = QRectF(local, m_rect.size());
	prepareGeometryChange();
	m_rect = delta;
	updateConnerPos();
}

void CustomRectItem::updateConnerPos()
{
	const QRectF rect = m_rect;
	for (auto item : m_HandlesList)
	{
		CornerDirction dir = item->getDir();
		switch (dir)
		{
		case Top:
			item->move((rect.topLeft()+rect.topRight())/2);
			break;
		case Right:
			item->move((rect.topRight()+ rect.bottomRight())/2);
			break;
		case Bottom:
			item->move((rect.bottomLeft()+ rect.bottomRight())/2);
			break;
		case Left:
			item->move((rect.topLeft()+ rect.bottomLeft())/2);
			break;
		case LeftTop:
			item->move(rect.topLeft());
			break;
		case LeftBottom:
			item->move(rect.bottomLeft());
			break;
		case RightTop:
			item->move(rect.topRight());
			break;
		case RightBottom:
			item->move(rect.bottomRight());
			break;
		}
	}
}

QRectF CustomRectItem::boundingRect() const
{
	return m_rect;
}

圆形实现也类似,只要理解了正矩形,圆形也一样。

因为所有的图形类都是在图像上画的,所以在图像Item中声明CustomItemBaseFactory* m_itemFactory;  使用的话就简单贴下代码 [具体请看下载链接的代码]:

m_rectFactory = new CustomRectItemFactory;

m_Scene->m_ImageItem->m_itemFactory = m_rectFactory;

总结

因为只是练习的demo,所以在完成正矩形,旋转矩形和圆形这三个图像就不在继续了,这里只是做个Mark,后面想继续在继续完善。

下载链接地址:

QtAppTest220104.zip-C/C++文档类资源-优快云下载

现在已经更新到这样的形式了,虽然感觉写复杂了,有部分还能继续优化,但就先这样吧,以后有心思再改了

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值