Qt QGraphicsView+QGraphicsScene+QGraphicsItem会跳舞的机器人
Qt 绘图
Qt | QGraphicsView+QGraphicsScene+QGraphicsItem会跳舞的机器人
该篇文章转载自Qt | QGraphicsView+QGraphicsScene+QGraphicsItem会跳舞的机器人
笔者主要是用来学习一下Qt中的绘图类。
QGraphicsView 是 Qt 框架中的一个重要组件,用于显示和交互 2D 图形项(QGraphicsItem)。它提供了一个高级的、可缩放的视图,适用于需要复杂图形交互的应用程序,如图形编辑器、地图查看器等。
以下是一些关于 GraphicsView 的关键点和示例代码:
关键类和方法
- QGraphicsView: 用于显示
QGraphicsScene中的内容。 - QGraphicsScene: 管理图形项的容器。
- QGraphicsItem: 图形项的基类,可以派生出各种具体的图形项,如
QGraphicsRectItem,QGraphicsEllipseItem等。
新建一个项目DanceRobot.
1.Main.cpp的源代码:
#include "mainwindow.h"
#include <QApplication>
// 图形视图类提供了一个用于显示图形场景的内容的小部件
#include<QGraphicsView>
// 提供了一个用于管理大量二维图形项的界面
#include<QGraphicsScene>
#include<cmath>
#include"qcoloritem.h"
#include"qrobot.h"
class QMyGraphicsView:public QGraphicsView
{
public:
// 使用基类的构造函数
using QGraphicsView::QGraphicsView;
protected:
// 重写resizeEvent方法,用于处理视图大小改变事件
void resizeEvent(QResizeEvent *event)
{
};
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 创建一个QGraphicsScene类型对象,设置其范围为(-200,-200,200,200),大小为400
QGraphicsScene scence(-200,-200,400,400);
for(int i = 0;i < 10;i++)
{
// 创建ColorItem对象
QColorItem* pItem = new QColorItem();
// 设置ColorItem对象的位置在 (-150,150)之间
pItem->setPos(std::sin((i/6.28)/10)*150,
std::cos((i/6.28)/10)*150);
scence.addItem(pItem);
}
QRobot* pRobot = new QRobot();
// 设置Robot对象变换,放大1.2倍
// pRobot->setTransform(QTransform::fromScale(1.2,1.2),true);
pRobot->setPos(0,-20);
scence.addItem(pRobot);
QGraphicsView view(&scence);
view.setRenderHint(QPainter::Antialiasing);
// 设置视图更新模式
view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
view.setBackgroundBrush(QBrush(Qt::yellow));
view.setWindowTitle("机器人");
view.show();
return a.exec();
}
2.新建一个类QColorItem,qcoloritem.h源代码如下:
#ifndef QCOLORITEM_H
#define QCOLORITEM_H
#include <QGraphicsItem>
#include <QColor>
class QColorItem : public QGraphicsItem
{
public:
explicit QColorItem(QGraphicsItem *parent = nullptr);
virtual QRectF boundingRect() const override;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
protected:
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
private:
QColor m_Color;
signals:
};
#endif // QCOLORITEM_H
qcolorite.cpp源代码如下:
#include "qcoloritem.h"
#include<QApplication>
#include<QRandomGenerator>
#include<QCursor>
#include<QPainter>
#include<QGraphicsSceneMouseEvent>
#include<QDrag>
#include<QMimeData>
#include<QImage>
#include<QPixmap>
#include<QLatin1Char>
#include<QWidget>
QColorItem::QColorItem(QGraphicsItem *parent)
: QGraphicsItem(parent)
,m_Color(QRandomGenerator::global()->bounded(256),
QRandomGenerator::global()->bounded(256),
QRandomGenerator::global()->bounded(256))
{
// 设置工具提示,显示颜色值和提示信息
setToolTip(QString("QColor(%1,%2,%3)\n%4").arg(m_Color.red()).arg(m_Color.green())
.arg(m_Color.blue()).arg(m_Color.alpha()));
// 设置光标为张开的手
setCursor(Qt::OpenHandCursor);
// 设置只接受鼠标左键事件
setAcceptedMouseButtons(Qt::LeftButton);
}
QRectF QColorItem::boundingRect() const
{
return QRectF(-15.5,-15.5,34,34);
}
void QColorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
// 忽略未使用的参数
Q_UNUSED(option);
Q_UNUSED(widget);
// 设置画笔为无
painter->setPen(Qt::NoPen);
// 设置画刷为灰黑色
painter->setBrush(Qt::darkGray);
// 绘制内圆
painter->drawEllipse(-12,-12,30,30);
painter->setPen(QPen(Qt::black,1));
painter->setBrush(QBrush(m_Color));
painter->drawEllipse(-15,-15,30,30);
}
void QColorItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
// 设置光标为闭合的手
setCursor(Qt::ClosedHandCursor);
}
void QColorItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
// 设置光标为张开的手
setCursor(Qt::OpenHandCursor);
}
void QColorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
// 如果鼠标移动的距离小于拖动起始距离,则不进行拖动
if(QLineF(event->scenePos(),event->buttonDownScreenPos(Qt::LeftButton)).length() < QApplication::startDragDistance())
{
return;
}
QDrag* pDrag = new QDrag(event->widget()); // 创建拖动对象
QMimeData* pMimiData = new QMimeData(); // 创建Mime对象
pDrag->setMimeData(pMimiData); // 设置拖动对象的MIME数据
static int n = 0;
if(n++ > 2 && QRandomGenerator::global()->bounded(3) == 0)
{
// 加载图像
QImage Image(":/Image/Head.png");
// 设置MIME数据为图像
pMimiData->setImageData(Image);
// 设置拖动对象的像素图
pDrag->setPixmap(QPixmap::fromImage(Image).scaled(30,40));
// 设置热点
pDrag->setHotSpot(QPoint(15,30));
}
else
{
// 设置MIME颜色
pMimiData->setColorData(m_Color);
// 设置文本
pMimiData->setText(QString("%1%2%3")
.arg(m_Color.red(),2,16,QLatin1Char('0'))
.arg(m_Color.green(),2,16,QLatin1Char('0'))
.arg(m_Color.blue(),2,16,QLatin1Char('0')));
// 创建像素图
QPixmap pixmap(34,34);
// 填充为白色
pixmap.fill(Qt::white);
// 创建画家对象
QPainter painter(&pixmap);
// 平移坐标系
painter.translate(15,15);
// 设置抗锯齿
painter.setRenderHint(QPainter::Antialiasing);
// 绘制图形项
paint(&painter,nullptr,nullptr);
// 结束绘制
painter.end();
// 设置掩码
pixmap.setMask(pixmap.createHeuristicMask());
// 设置拖动对象像素图
pDrag->setPixmap(pixmap);
// 设置热点
pDrag->setHotSpot(QPoint(15,30));
}
// 执行拖动操作
pDrag->exec();
// 设置光标为张开的手
setCursor(Qt::OpenHandCursor);
}
3.添加qrobot.h头文件,qrobot.h源代码如下:
#ifndef QROBOT_H
#define QROBOT_H
#include<QGraphicsItem>
#include<QPixmap>
QT_BEGIN_NAMESPACE
class QGraphicsSceneMouseEvent;
class QParalleAnimationGroup;
QT_END_NAMESPACE
class QRobotPart:public QGraphicsObject
{
public:
QRobotPart(QGraphicsItem* pParent = nullptr);
protected:
virtual void dropEvent(QGraphicsSceneDragDropEvent *event) override;
virtual void dragEnterEvent(QGraphicsSceneDragDropEvent *event) override;
virtual void dragLeaveEvent(QGraphicsSceneDragDropEvent *event) override;
QColor m_Color = Qt::lightGray;
bool m_bDragOver = false;
};
class QRobotHead:public QRobotPart
{
public:
QRobotHead(QGraphicsItem* pParent = nullptr);
virtual QRectF boundingRect() const override;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
protected:
virtual void dragEnterEvent(QGraphicsSceneDragDropEvent *event) override;
virtual void dropEvent(QGraphicsSceneDragDropEvent *event) override;
private:
QPixmap m_pixmap;
};
class QRobotTorso:public QRobotPart
{
public:
using QRobotPart::QRobotPart;
virtual QRectF boundingRect() const override;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
};
class QRobotLimb:public QRobotPart
{
public:
QRobotLimb(QGraphicsItem* pParent = nullptr );
virtual QRectF boundingRect() const override;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
};
class QRobot:public QRobotPart
{
public:
QRobot(QGraphicsItem* pParent = nullptr );
virtual QRectF boundingRect() const override;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
};
#endif // QROBOT_H
qrobot.cpp源代码如下:
#include"qrobot.h"
#include<QGraphicsSceneDragDropEvent>
#include<QMimeData>
#include<QPainter>
#include<QParallelAnimationGroup>
#include<QPropertyAnimation>
QRobotPart::QRobotPart(QGraphicsItem *pParent)
:QGraphicsObject(pParent)
,m_Color(Qt::lightGray)
{
// 设置接受拖放事件
setAcceptDrops(true);
}
void QRobotPart::dropEvent(QGraphicsSceneDragDropEvent *event)
{
m_bDragOver = false;
if(event->mimeData()->hasColor())
{
// 设置颜色
m_Color = qvariant_cast<QColor>(event->mimeData()->colorData());
update();
}
}
void QRobotPart::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
if(event->mimeData()->hasColor())
{
// 接收事件
event->setAccepted(false);
// 拖放标志
m_bDragOver = true;
update();
}
else
{
event->setAccepted(false);
}
}
void QRobotPart::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
{
Q_UNUSED(event);
m_bDragOver = false; // 清除拖放事件
update();
}
QRobotHead::QRobotHead(QGraphicsItem* pParent)
:QRobotPart(pParent)
{
}
QRectF QRobotHead::boundingRect() const
{
// 返回头部边界
return QRectF(-15,50,30,50);
}
void QRobotHead::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(option);
if(m_pixmap.isNull())
{
painter->setBrush(m_bDragOver? m_Color.lighter(130):m_Color);
// 绘制圆角矩形
painter->drawRoundedRect(10,30,20,30,25,25,Qt::RelativeSize);
painter->setBrush(Qt::white);
painter->drawEllipse(-7,-23, 7, 7);
painter->drawEllipse(0,-23, 7, 7);
painter->setBrush(Qt::black);
painter->drawEllipse(-5,-21, 2, 2);
painter->drawEllipse(2,-1, 2, 2);
painter->setPen(QPen(Qt::black,2));
painter->setBrush(Qt::NoBrush);
painter->drawArc(-6,-22,12,15,190*16,160*16);
}
else
{
// 缩放画布
painter->scale(.2272,.2824);
painter->drawPixmap(QPointF(-15*4.4,-50*3.54),m_pixmap);
}
}
void QRobotHead::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
if(event->mimeData()->hasImage())
{
// 接收事件
event->setAccepted(false);
// 拖放标志
m_bDragOver = true;
update();
}
else
{
QRobotPart::dragEnterEvent(event);
}
}
void QRobotHead::dropEvent(QGraphicsSceneDragDropEvent *event)
{
if(event->mimeData()->hasImage())
{
// 拖放标志
m_bDragOver = false;
m_pixmap = qvariant_cast<QPixmap>(event->mimeData()->imageData());
update();
}
else
{
QRobotPart::dropEvent(event);
}
}
QRectF QRobotTorso::boundingRect() const
{
// 返回头部边界
return QRectF(-30,20,60,60);
}
void QRobotTorso::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(option);
painter->setBrush(m_bDragOver? m_Color.lighter(130):m_Color);
// 绘制圆角矩形
painter->drawRoundedRect(-20,-20,40,60,25,25,Qt::RelativeSize);
painter->drawEllipse(-25,-20, 20, 20); // 绘制左肩
painter->drawEllipse(5,-20, 20, 20); // 绘制右肩
painter->drawEllipse(-20,22, 20, 20); // 绘制左腰
painter->drawEllipse(0,22, 20, 20); // 绘制右腰
}
QRobotLimb::QRobotLimb(QGraphicsItem* pParent)
:QRobotPart(pParent)
{
}
QRectF QRobotLimb::boundingRect() const
{
// 返回头部边界
return QRectF(-5,-5,40,10);
}
void QRobotLimb::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(option);
painter->setBrush(m_bDragOver? m_Color.lighter(130):m_Color);
// 绘制圆角矩形
painter->drawRoundedRect(boundingRect(),50,50,Qt::RelativeSize);
painter->drawEllipse(-5,-5, 10, 10); // 绘制关节
}
QRobot::QRobot(QGraphicsItem* pParent)
:QRobotPart(pParent)
{
// 设置图形项无内容
setFlags(ItemHasNoContents);
// 创建躯干
QGraphicsObject* pTorsoItem = new QRobotTorso(this);
QGraphicsObject* pHeadItem = new QRobotHead(pTorsoItem);
QGraphicsObject* pUpperLeftArmItem = new QRobotLimb(pTorsoItem);
QGraphicsObject* pLowLeftArmItem = new QRobotLimb(pUpperLeftArmItem);
QGraphicsObject* pUpperRightArmItem = new QRobotLimb(pTorsoItem);
QGraphicsObject* pLowRightArmItem = new QRobotLimb(pUpperRightArmItem);
QGraphicsObject* pUpperRightLegItem = new QRobotLimb(pTorsoItem);
QGraphicsObject* pLowRightLegItem = new QRobotLimb(pUpperRightLegItem);
QGraphicsObject* pUpperLeftLegItem = new QRobotLimb(pTorsoItem);
QGraphicsObject* pLowLeftLegItem = new QRobotLimb(pUpperLeftLegItem);
pHeadItem->setPos(0,-18);
pUpperLeftArmItem->setPos(-15,-10);
pLowLeftArmItem->setPos(30,0);
pUpperRightArmItem->setPos(15,-10);
pLowRightArmItem->setPos(30,0);
pUpperRightLegItem->setPos(10,32);
pLowRightLegItem->setPos(30,0);
pUpperLeftLegItem->setPos(-10,32);
pLowLeftLegItem->setPos(30,0);
QParallelAnimationGroup* pAnimation = new QParallelAnimationGroup(this);
QPropertyAnimation* pHeadAnimation = new QPropertyAnimation(pHeadItem,"rotation");
pHeadAnimation->setStartValue(20);
pHeadAnimation->setEndValue(-20);
QPropertyAnimation* pHeadScaleAnimation = new QPropertyAnimation(pHeadItem,"scale");
pHeadScaleAnimation->setEndValue(1.1);
pAnimation->addAnimation(pHeadAnimation);
pAnimation->addAnimation(pHeadScaleAnimation);
QPropertyAnimation* pUpperLeftArmAnimation = new QPropertyAnimation(pUpperLeftArmItem,"rotation");
pUpperLeftArmAnimation->setStartValue(190);
pUpperLeftArmAnimation->setEndValue(180);
pAnimation->addAnimation(pUpperLeftArmAnimation);
QPropertyAnimation* pLowerLeftArmAnimation = new QPropertyAnimation(pLowLeftArmItem,"rotation");
pLowerLeftArmAnimation->setStartValue(50);
pLowerLeftArmAnimation->setEndValue(10);
pAnimation->addAnimation(pLowerLeftArmAnimation);
QPropertyAnimation* pUpperRightArmAnimation = new QPropertyAnimation(pUpperRightArmItem,"rotation");
pUpperRightArmAnimation->setStartValue(300);
pUpperRightArmAnimation->setEndValue(310);
pAnimation->addAnimation(pUpperRightArmAnimation);
QPropertyAnimation* pLowerRightArmAnimation = new QPropertyAnimation(pLowRightArmItem,"rotation");
pLowerRightArmAnimation->setStartValue(0);
pLowerRightArmAnimation->setEndValue(-70);
pAnimation->addAnimation(pLowerRightArmAnimation);
QPropertyAnimation* pUpperLeftLegAnimation = new QPropertyAnimation(pUpperRightLegItem,"rotation");
pUpperLeftLegAnimation->setStartValue(150);
pUpperLeftLegAnimation->setEndValue(80);
pAnimation->addAnimation(pUpperLeftLegAnimation);
QPropertyAnimation* pLowerLeftLegAnimation = new QPropertyAnimation(pLowRightLegItem,"rotation");
pLowerLeftLegAnimation->setStartValue(70);
pLowerLeftLegAnimation->setEndValue(10);
pAnimation->addAnimation(pLowerLeftLegAnimation);
QPropertyAnimation* pUpperRightLegAnimation = new QPropertyAnimation(pUpperLeftLegItem,"rotation");
pUpperRightLegAnimation->setStartValue(40);
pUpperRightLegAnimation->setEndValue(120);
pAnimation->addAnimation(pUpperRightLegAnimation);
QPropertyAnimation* pLowerRightLegAnimation = new QPropertyAnimation(pLowLeftLegItem,"rotation");
pLowerRightLegAnimation->setStartValue(10);
pLowerRightLegAnimation->setEndValue(50);
pAnimation->addAnimation(pLowerRightLegAnimation);
QPropertyAnimation* pTorsoAnimation = new QPropertyAnimation(pTorsoItem,"rotation");
pTorsoAnimation->setStartValue(5);
pTorsoAnimation->setEndValue(-20);
pAnimation->addAnimation(pTorsoAnimation);
for(int i=0;i<pAnimation->animationCount();i++)
{
QPropertyAnimation* pAnim = qobject_cast<QPropertyAnimation*>(pAnimation->animationAt(i));
pAnim->setEasingCurve(QEasingCurve::SineCurve);
pAnim->setDuration(2000);
}
pAnimation->setLoopCount(-1);
pAnimation->start();
}
QRectF QRobot::boundingRect() const
{
return QRectF();
}
void QRobot::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(painter);
Q_UNUSED(option);
Q_UNUSED(widget);
}
项目的显示效果如下:

好了,项目介绍到这里。项目源代码:DanceRobot
该项目用到的类有:
QRandomGenerator:QRandomGenerator 类是 Qt 框架中的一个工具类,用于生成随机数。这个类提供了一个简单易用的接口来获取随机值,这些值来自于一个高质量的随机数生成器(RNG)
**QDrag:**QDrag 类为基于 MIME (多用途 Internet 邮件扩展) 的拖放数据传输提供支持。
QMimeData:QMimeData 类在 Qt 中用于表示和存储拖放操作中传输的数据。它是一个抽象类,提供了一种机制来封装不同类型的数据,这些数据可以是文本、图片、文件链接等。
QLatin1Char:QLatin1Char 类在 Qt 中是一个方便的辅助类,它用于表示单个 Latin-1(ISO-8859-1)字符。这个类的主要作用是提供对 Latin-1 字符集中的字符进行快速访问和操作。
QParalleAnimationGroup:QParallelAnimationGroup 类是 Qt 动画框架中的一个并行动画容器组。当启动 QParallelAnimationGroup 时,它会同时启动组内所有的动画,即所有动画并行运行。这个动画组会在持续时间最长的动画结束时完成。你可以像对待任何其他 QAbstractAnimation 一样对待 QParallelAnimationGroup,例如,可以暂停、恢复或将其添加到其他动画组中。
QGraphicsObject:QGraphicsObject 类是 Qt 的图形视图框架中的一个抽象基类,用于表示可以被绘制到 QGraphicsScene 中的任何对象。它是 QGraphicsItem 的一个子类,专门用于表示具有绘图和事件处理能力的对象。
QPropertyAnimation:QPropertyAnimation 类是 Qt 中用于创建动画的一个类,它通过变化对象的属性值来实现动画效果。
qvariant_cast:qvariant_cast 是 Qt 中的一个模板函数,它用于将 QVariant 对象转换为特定的类型。如果 QVariant 可以转换为请求的类型,qvariant_cast 会返回转换后的值;如果转换失败,它会返回默认构造的值。这与 QVariant::value 函数的作用相同,但 qvariant_cast 在类型转换失败时不会抛出异常,而是返回默认值,这使得它在某些情况下比 QVariant::value 更安全。
qobject_cast:qobject_cast 是 Qt 提供的一个模板函数,用于在运行时将 QObject 类型的指针或引用转换为它的派生类指针或引用。这个函数类似于 C++ 的 dynamic_cast,但它不需要运行时类型信息(RTTI),因此可以在不支持 RTTI 或禁用 RTTI 的情况下使用。
好了,项目介绍到这里。
Qt 的图形视图框架中的一个抽象基类,用于表示可以被绘制到 QGraphicsScene 中的任何对象。它是 QGraphicsItem 的一个子类,专门用于表示具有绘图和事件处理能力的对象。
QPropertyAnimation:QPropertyAnimation 类是 Qt 中用于创建动画的一个类,它通过变化对象的属性值来实现动画效果。
qvariant_cast:qvariant_cast 是 Qt 中的一个模板函数,它用于将 QVariant 对象转换为特定的类型。如果 QVariant 可以转换为请求的类型,qvariant_cast 会返回转换后的值;如果转换失败,它会返回默认构造的值。这与 QVariant::value 函数的作用相同,但 qvariant_cast 在类型转换失败时不会抛出异常,而是返回默认值,这使得它在某些情况下比 QVariant::value 更安全。
qobject_cast:qobject_cast 是 Qt 提供的一个模板函数,用于在运行时将 QObject 类型的指针或引用转换为它的派生类指针或引用。这个函数类似于 C++ 的 dynamic_cast,但它不需要运行时类型信息(RTTI),因此可以在不支持 RTTI 或禁用 RTTI 的情况下使用。
更多推荐
所有评论(0)