自定义QGraphicsItem

前言:

本文参考https://blog.csdn.net/liang19890820/article/details/53132180

简述

继承 QGraphicsItem,自定义item。

自定义 QGraphicsItem

要实现自定义 item,需要覆盖 QGraphicsItem 的两个纯虚函数:

void paint()

QRectF boundingRect()

​ 注意:坐标为item坐标系

tips:关于信号/槽、事件、算法相关的内容,本节暂时不做讲解,放到后面章节。

BoundingRect() 和 Shape()的区别

参照模型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iBI6X7CX-1592123801128)(E:\csdn博客备份%5CUsers%5CWGJ%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1592121226979.png)]

要实现这个效果很简单,可以逐步分解:

  • 整体(最外侧的圆)
  • 眼睛(左眼/右眼)
  • 嘴(笑容)

分别计算出各部分的区域坐标、大小,然后根据形状进行绘制。

上述图案标识的是绝对位置,为了适应各种大小, 可以进行比例及相对位置换算,将各部分进行逐一转换。

使用示例

效果

下图显示了 3 个不同大小的笑脸:(不好意思,为了简便,没画眼球,成了柯大侠了,哈哈。)

在这里插入图片描述

源码

SmileItem.h:

#pragma once

#include <QGraphicsItem>
#include <QRectF>

class SmileItem : public QGraphicsItem
{
public:
	explicit SmileItem(QGraphicsItem* parent = NULL);
	explicit SmileItem(const QRectF & rect, QGraphicsItem * parent);
	explicit SmileItem(qreal x, qreal y, qreal w, qreal h, QGraphicsItem * parent);

	QRectF rect() const;

	void setRect(const QRectF & rect);

	~SmileItem();

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


private:
	QRectF m_rect;

	mutable QRectF m_boundingRect;

	void updateRect();

	inline void setRect(qreal ax, qreal ay, qreal w, qreal h);


	// 缩放比例
	double m_dScale;

	// 左眼、右眼、嘴的中点
	QPointF m_leftEyeCenter;
	QPointF m_rightEyecenter;
	QPointF m_smileCenter;

	// 眼睛的宽度、高度
	double m_dEyeWidth;
	double m_dEyeHeight;
	
	// 嘴的高度、宽度
	double m_dSmileWidth;
	double m_dSmileHeight;
};

SmileItem.cpp:

#include "SmileItem.h"
#include <QPainter>

SmileItem::SmileItem(QGraphicsItem  *parent)
	: QGraphicsItem(parent)
{
	setRect(QRect(-50,-50,100,100));
}

SmileItem::~SmileItem()
{
}
SmileItem::SmileItem(const QRectF &rect, QGraphicsItem *parent)
	: QGraphicsItem(parent)
{
	setRect(rect);
}
SmileItem::SmileItem(qreal x, qreal y, qreal w, qreal h, QGraphicsItem *parent)
	: QGraphicsItem(parent)
{
	setRect(x, y, w, h);
}

QRectF SmileItem::rect() const
{
	return m_rect;
}

void SmileItem::setRect(const QRectF &rect)
{
	if (m_rect == rect)
		return;

	prepareGeometryChange(); //正如 setRect(),无论以任何方式更改 item 的几何形状,必须首先调用prepareGeometryChange(),以保证 QGraphicsScene 中的索引是最新的。
	m_rect = rect;
	m_boundingRect = QRectF(); //m_boundingRect为空
	updateRect();
	
	update(); //调用paintEvent重绘
}

QRectF SmileItem::boundingRect() const
{
	if (m_boundingRect.isNull())
		m_boundingRect = m_rect;

	return m_boundingRect;
}

//则会调用 updateRect() 来重新计算笑脸中各个部位的坐标、大小
void SmileItem::updateRect()
{
	// 缩放比例
	m_dScale = m_rect.width() / 100.0;
	//m_dScale = 1;

	// 左眼的中点
	m_leftEyeCenter.setX(-15 * m_dScale);
	m_leftEyeCenter.setY(-25 * m_dScale);

	// 右眼的中点
	m_rightEyecenter.setX(15 * m_dScale);
	m_rightEyecenter.setY(-25 * m_dScale);

	// 嘴的中点
	m_smileCenter.setX(0);
	m_smileCenter.setY(10 * m_dScale);

	// 眼睛的宽度、高度(宽度的 2 倍)
	m_dEyeWidth = m_rect.width() / (100.0 / 12);
	m_dEyeHeight = m_dEyeWidth * 2;

	// 嘴的高度、宽度
	m_dSmileWidth = m_rect.width() / (100.0 / 66);
	m_dSmileHeight = m_rect.height() / (100.0 / 50);
	
}

inline void SmileItem::setRect(qreal ax, qreal ay, qreal w, qreal h)
{
	setRect(QRectF(ax, ay, w, h));
}

void SmileItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
	Q_UNUSED(option);
	Q_UNUSED(widget);

	// 反走样
	painter->setRenderHint(QPainter::Antialiasing, true);

	// 脸
	painter->setPen(Qt::NoPen);
	painter->setBrush(Qt::yellow);
	painter->drawEllipse(m_rect);

	// 左眼
	painter->setPen(QPen(Qt::black));
	painter->setBrush(Qt::white);
	painter->drawEllipse(
		QRectF(m_leftEyeCenter.x() - m_dEyeWidth / 2, 
			m_leftEyeCenter.y() - m_dEyeHeight / 2,
			m_dEyeWidth, m_dEyeHeight));	

	// 右眼
	painter->setPen(QPen(Qt::black));
	painter->setBrush(Qt::white);
	painter->drawEllipse(
		QRectF(m_rightEyecenter.x() - m_dEyeWidth / 2, 
			m_rightEyecenter.y() - m_dEyeHeight / 2, 
			m_dEyeWidth, m_dEyeHeight));	

	// 嘴 - 笑容
	painter->setPen(QPen(Qt::red));
	painter->setBrush(Qt::NoBrush);

	//QPainterPath
	QPainterPath path;
	path.arcMoveTo(
		QRectF(-m_dSmileWidth / 2,
			-(m_dSmileHeight / 2 - m_smileCenter.y()),
			m_dSmileWidth, m_dSmileHeight), 
		0);
	path.arcTo(QRectF(-m_dSmileWidth / 2,
		-(m_dSmileHeight / 2 - m_smileCenter.y()), 
		m_dSmileWidth, m_dSmileHeight), 0, -180);
	painter->drawPath(path);
}

main.cpp

#include "QtWidgetsApplication1.h"
#include <QtWidgets/QApplication>
#include <QGraphicsSimpleTextItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include "SmileItem.h"


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

	SmileItem *pItem = new SmileItem();
	pItem->setRect(QRect(-25, -25, 50, 50));
	pItem->setPos(-100, 50); //项在场景中的位置
	//疑问:item为什么还能显示全?

	SmileItem *pItem2 = new SmileItem();
	pItem2->setRect(QRect(-50, -50, 100, 100));
	pItem2->setPos(100, 50);

	SmileItem *pItem3 = new SmileItem();
	pItem3->setRect(QRect(-75, -75, 150, 150));
	pItem3->setPos(250, 50);

	// 将笑脸添加至场景中
	QGraphicsScene *pScene = new QGraphicsScene();
	pScene->addItem(pItem);
	pScene->addItem(pItem2);
	pScene->addItem(pItem3);

	// 为视图设置场景
	QGraphicsView *pView = new QGraphicsView();
	pView->setScene(pScene);
	pView->show();
	qDebug() << pScene->sceneRect(); //答案:item为什么还能显示全?


    return a.exec();
}

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
自定义QGraphicsItem,可以继承QGraphicsItem类,并在派生类中实现paint()和boundingRect()函数。 paint()函数用于绘制图形元素,您可以使用QPainter类绘制自己的形状、文本、图像等。boundingRect()函数返回该图形元素的边界矩形,它用于定义该图形元素的碰撞检测区域。 以下是一个简单的例子: ```python from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import * class CustomItem(QGraphicsItem): def __init__(self, parent=None): super().__init__(parent) def boundingRect(self): return QRectF(-50, -50, 100, 100) def paint(self, painter, option, widget): painter.setBrush(QColor(255, 0, 0)) painter.drawEllipse(-50, -50, 100, 100) ``` 在这个例子中,我们继承了QGraphicsItem类,并实现了boundingRect()和paint()函数。boundingRect()函数返回一个100x100的矩形,paint()函数绘制了一个红色的圆形。 然后,您可以将这个自定义图形元素添加到 QGraphicsScene 中,并在 QGraphicsView 中显示它: ```python from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import * class CustomItem(QGraphicsItem): def __init__(self, parent=None): super().__init__(parent) def boundingRect(self): return QRectF(-50, -50, 100, 100) def paint(self, painter, option, widget): painter.setBrush(QColor(255, 0, 0)) painter.drawEllipse(-50, -50, 100, 100) if __name__ == '__main__': app = QApplication([]) scene = QGraphicsScene() item = CustomItem() scene.addItem(item) view = QGraphicsView(scene) view.show() app.exec_() ``` 这个例子创建了一个 QGraphicsScene,然后创建了一个CustomItem对象,并将其添加到场景中。最后,创建了一个 QGraphicsView 对象,并将场景设置为其父级。运行这个程序,您将看到一个红色圆形在视图中心。 这只是自定义QGraphicsItem的基础,您可以使用更复杂的绘图和交互技术来实现更高级的图形元素。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值