本文参考https://blog.csdn.net/liang19890820/article/details/53132180
继承 QGraphicsItem,自定义item。
要实现自定义 item,需要覆盖 QGraphicsItem 的两个纯虚函数:
void paint()
QRectF boundingRect()
注意:坐标为item坐标系
tips:关于信号/槽、事件、算法相关的内容,本节暂时不做讲解,放到后面章节。
要实现这个效果很简单,可以逐步分解:
分别计算出各部分的区域坐标、大小,然后根据形状进行绘制。
上述图案标识的是绝对位置,为了适应各种大小, 可以进行比例及相对位置换算,将各部分进行逐一转换。
下图显示了 3 个不同大小的笑脸:(不好意思,为了简便,没画眼球,成了柯大侠了,哈哈。)
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();
}