自定义QGraphicsItem

文章目录

  • 前言:
  • 简述
  • 自定义 QGraphicsItem
  • BoundingRect() 和 Shape()的区别
  • 参照模型
  • 使用示例
    • 效果
    • 源码

前言:

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

简述

继承 QGraphicsItem,自定义item。

自定义 QGraphicsItem

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

void paint()

QRectF boundingRect()

​ 注意:坐标为item坐标系

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

BoundingRect() 和 Shape()的区别

参照模型

自定义QGraphicsItem_第1张图片

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

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

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

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

使用示例

效果

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

自定义QGraphicsItem_第2张图片

源码

SmileItem.h:

#pragma once

#include 
#include 

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 

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 
#include 
#include 
#include 
#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(10, 50); //项在场景中的位置

	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();

    return a.exec();
}

你可能感兴趣的:(Qt)