qt-C++笔记之自定义绘制:QWidget中的paintEvent 与 QGraphicsItem中的paint
qt-C++笔记之自定义绘制:QWidget中的paintEvent 与 QGraphicsItem中的paint
code review!
文章目录
- qt-C++笔记之自定义绘制:QWidget中的paintEvent 与 QGraphicsItem中的paint
- 1. 概述
- 2. QWidget 的 paintEvent
- 2.1. 基本概念
- 2.2. 典型用法
- 2.3. 关键点详解
- 2.3.1. 参数 QPaintEvent
- 2.3.2. 使用 QPainter
- 2.3.3. 绘制区域
- 2.3.4. 性能注意事项
- 2.4. 常用绘制方法
- 2.5. 触发重绘
- 2.6. 实用小贴士
- 2.7. 常见问题
- 2.8. 调用时机
- 3. QGraphicsItem 自定义绘制
- 3.1. 核心方法
- 3.2. 简单示例
- 3.3. 使用示例
- 3.4. 注意事项
- 3.5. 进阶:响应事件
- 3.6. 常见问题
- 4. QWidget paintEvent vs QGraphicsItem paint 对比
- 4.1. 简要说明
- 4.2. 基本概述
- 4.3. 参数对比
- 4.4. 调用机制和时机
- 4.5. 实现方式和代码示例
- 4.5.1. QWidget paintEvent 示例
- 4.5.2. QGraphicsItem paint 示例
- 4.6. 性能和适用场景
- 4.7. 优缺点总结
- 5. 自定义 QGraphicsRectItem
- 5.1. 基础模板
- 5.2. 使用示例
- 5.3. 常用 Flags
- 5.4. 常见扩展
- 6. 自定义 QGraphicsItem vs QGraphicsRectItem 对比
- 6.1. 说明
- 6.2. QGraphicsItem 示例
- 6.3. QGraphicsRectItem 示例
- 6.4. 代码对比要点
- 6.5. 使用场景对比
- 6.6. 优缺点对比
- 6.7. 适用场景区别
1. 概述
Qt 提供两种主要自定义绘制机制:QWidget
的 paintEvent
用于传统 UI 部件的像素级绘制,适合简单控件自定义;QGraphicsItem
的 paint
用于 Graphics View 框架中的图形项,适合复杂场景、动画和交互。两者均依赖 QPainter
进行绘制,但上下文、参数和优化不同。以下从 QWidget
开始,逐步扩展到 Graphics View。
2. QWidget 的 paintEvent
2.1. 基本概念
paintEvent
是 QWidget
及其子类(如 QMainWindow
、QLabel
)中的虚函数,用于处理控件绘制事件。每当控件需要重绘时(如窗口最小化恢复、调用 update()
或 repaint()
),Qt 自动调用该函数。
2.2. 典型用法
继承 QWidget
,重写 paintEvent
:
#include <QWidget>
#include <QPainter>class MyWidget : public QWidget {Q_OBJECT
public:explicit MyWidget(QWidget *parent = nullptr) : QWidget(parent) {}protected:void paintEvent(QPaintEvent *event) override {QPainter painter(this);painter.setPen(Qt::blue);painter.drawRect(rect());painter.drawText(10, 30, "Hello, Qt!");}
};
2.3. 关键点详解
2.3.1. 参数 QPaintEvent
QPaintEvent *event
提供了需要重绘的区域(event->rect()
),但你通常不需要直接用它,除非优化重绘性能。
2.3.2. 使用 QPainter
- 必须在
paintEvent
里创建QPainter
,并以当前 widget 为参数:QPainter painter(this);
QPainter
是所有绘制操作的入口,可以画线、画图、画文字等。
2.3.3. 绘制区域
paintEvent
只在需要时自动调用,不要手动调用,如需重绘用update()
触发。
2.3.4. 性能注意事项
- 因为该函数会频繁调用,如果处理慢会导致界面卡顿。
2.4. 常用绘制方法
void paintEvent(QPaintEvent *event) override {QPainter painter(this);// 绘制直线painter.setPen(QPen(Qt::red, 2));painter.drawLine(10, 10, 100, 100);// 绘制矩形painter.setBrush(Qt::green);painter.drawRect(120, 10, 80, 60);// 绘制椭圆painter.setBrush(Qt::yellow);painter.drawEllipse(220, 10, 80, 60);// 绘制文字painter.setPen(Qt::black);painter.drawText(10, 90, "这是文字");
}
2.5. 触发重绘
- 主动调用
update()
或repaint()
可让 Qt 重新调用paintEvent
。 update()
:异步请求重绘,提高效率。repaint()
:同步立即重绘,不推荐频繁使用。
this->update(); // 请求重绘
2.6. 实用小贴士
- 仅在
paintEvent
内使用QPainter
绘制 widget。 - 减少
paintEvent
内逻辑,只专注绘制。 - 用
QPixmap
/QImage
缓存复杂绘制(双缓冲)。
2.7. 常见问题
- 绘制不显示:未重写
paintEvent
,或QPainter
使用不当。 - 操作 UI:不建议在
paintEvent
内更改 UI 状态,仅绘制。
2.8. 调用时机
paintEvent
由 Qt 自动调用,不手动调用。常见触发:
- 窗口首次显示或从最小化/隐藏恢复。
- 窗口被遮挡后暴露。
- 主动请求:
update()
(异步)或repaint()
(同步)。 - 窗口大小改变(resize)。
示意流程:
外部事件/代码|v
窗口需要重绘(如显示/恢复/遮挡/resize/update())|v
Qt 事件系统检测|v
Qt 自动调用 paintEvent|v
自定义绘制逻辑
代码演示(按钮触发重绘):
#include <QWidget>
#include <QPainter>
#include <QPushButton>class MyWidget : public QWidget {Q_OBJECT
public:MyWidget(QWidget *parent = nullptr) : QWidget(parent) {auto btn = new QPushButton("重绘", this);btn->move(10, 10);connect(btn, &QPushButton::clicked, this, [this](){this->update(); // 触发 paintEvent});}protected:void paintEvent(QPaintEvent *event) override {QPainter painter(this);painter.setPen(Qt::blue);painter.drawRect(rect());painter.drawText(10, 50, "每次重绘都会调用 paintEvent");}
};
3. QGraphicsItem 自定义绘制
QGraphicsItem
是 Graphics View 框架的基础元素,用于 QGraphicsScene
中的可视对象。自定义绘制通过重写 paint()
实现,与 paintEvent
不同,无事件参数。
3.1. 核心方法
必须重写:
QRectF boundingRect() const
:返回边界矩形(重绘区域、碰撞检测)。void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr)
:具体绘制逻辑。
3.2. 简单示例
#include <QGraphicsItem>
#include <QPainter>class MyItem : public QGraphicsItem {
public:QRectF boundingRect() const override {return QRectF(0, 0, 100, 100);}void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override {painter->setBrush(Qt::blue);painter->drawRect(0, 0, 100, 100);painter->setPen(Qt::white);painter->drawText(QPointF(10, 50), "Hello, GraphicsItem");}
};
3.3. 使用示例
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);QGraphicsScene scene;scene.setSceneRect(0, 0, 400, 300);MyItem *item = new MyItem();scene.addItem(item);QGraphicsView view(&scene);view.show();return a.exec();
}
3.4. 注意事项
boundingRect()
必须包含所有绘制内容,否则裁剪。paint()
使用传入的QPainter
,类似paintEvent
但无事件。- 不要手动调用
paint()
,用update()
触发。 - 用
setFlag()
设置交互:如ItemIsMovable
(可移动)、ItemIsSelectable
(可选中)。
3.5. 进阶:响应事件
重写事件函数:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override {update(); // 触发重绘
}
3.6. 常见问题
- 图形不显示:
boundingRect()
不足大,或paint()
绘制错误。 - 交互无响应:未设置相应 flag,如
setFlag(QGraphicsItem::ItemIsMovable)
。
4. QWidget paintEvent vs QGraphicsItem paint 对比
对比项 | QWidget 的 paintEvent | QGraphicsItem 的 paint |
---|---|---|
所属体系 | Qt Widget(窗口部件)体系 | Qt Graphics View(图形视图)体系 |
重绘入口函数 | void paintEvent(QPaintEvent *event) | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
坐标系原点 | 控件左上角为 (0, 0) | 图元自身的局部坐标系,左上角通常为 (0,0) |
绘制对象获取 | QPainter painter(this); | Qt 自动传入 QPainter* painter |
区域定义 | 由控件大小决定(rect() ) | 必须重写 boundingRect() 明确区域 |
自动重绘触发 | 控件需要重绘时由 Qt 自动调用 | 图元需要重绘时由场景/视图自动调用 |
手动触发重绘 | 调用 update() 或 repaint() | 调用 update() 或 scene()->update(item) |
事件参数 | 有 QPaintEvent* event ,可获取待重绘区域 | 无需事件参数,需用 boundingRect() 约束区域 |
层级/叠加 | 控件之间由父子关系和 Z 轴顺序管理 | 图元可设置 zValue() 控制叠加顺序 |
变换(旋转、缩放等)支持 | 需手动变换 QPainter,较为繁琐 | 支持 setRotation() 、setScale() 等属性 |
交互与事件处理 | 事件函数如 mousePressEvent 在 QWidget 里处理 | 需在 QGraphicsItem 派生类中重写相关事件函数 |
适用场景 | 常规 UI 控件自定义绘制、轻量级定制 | 复杂场景、动画、游戏、可视化、交互图元等 |
4.1. 简要说明
- QWidget 的
paintEvent
适合界面元素的自定义绘制,如按钮、面板、输入框等。 - QGraphicsItem 的
paint
适合需要大量图形对象、自由变换、复杂交互的场景,如图形编辑器、动画场景、拓扑图等。
4.2. 基本概述
-
QWidget::paintEvent(QPaintEvent *event):
- 这是一个虚函数(virtual),在
QWidget
及其子类(如QLabel
、QPushButton
或自定义部件)中用于处理绘制事件。 - 当部件需要重绘时(如窗口调整大小、更新内容或外部触发
update()
/repaint()
时),Qt会自动调用此方法。 - 它是Qt Widgets框架的核心,用于绘制UI元素的像素级内容。你可以重载它来实现自定义绘制,但不是纯虚函数(即不需要必须实现,除非你想自定义)。
- 这是一个虚函数(virtual),在
-
QGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget):
- 这是一个纯虚函数(pure virtual),在
QGraphicsItem
及其子类(如QGraphicsRectItem
、QGraphicsEllipseItem
或自定义项)中必须实现。 - 它用于绘制图形项的外观,这些项是
QGraphicsScene
的一部分,由QGraphicsView
视图渲染。 - Qt Graphics View框架更适合处理大量图形元素、变换(旋转、缩放)、碰撞检测和动画,而非传统UI部件。
- 这是一个纯虚函数(pure virtual),在
关键区别:paintEvent
是针对独立UI部件的"被动"重绘机制,而paint
是针对图形场景中项的"主动"绘制接口,前者更注重部件的整体渲染,后者更注重项的局部绘制和优化。
4.3. 参数对比
-
paintEvent:
- 参数:
QPaintEvent *event
– 提供重绘事件的信息,如需要重绘的区域(event->rect()
或event->region()
),以便优化只绘制变化部分。 - 你需要手动创建
QPainter
对象(通常在方法体内,如QPainter painter(this);
),并在部件的坐标系中绘制。
- 参数:
-
paint:
- 参数:
QPainter *painter
– Qt提供的现成画家对象,已准备好用于绘制(无需手动创建)。const QStyleOptionGraphicsItem *option
– 提供项的样式、状态(如是否选中、暴露区域option->exposedRect
)和变换信息,帮助实现样式一致性和优化。QWidget *widget
– 指向渲染该项的视图部件(通常为nullptr
,除非需要特定上下文)。
- 绘制发生在项的局部坐标系中,Qt会自动处理场景级变换。
- 参数:
区别:paintEvent
的参数更简单,焦点在事件上;paint
的参数更丰富,支持高级优化和样式集成。
4.4. 调用机制和时机
-
paintEvent:
- 由Qt的事件循环自动调用,通常在以下情况:
- 部件首次显示。
- 调用
update()
(异步重绘)或repaint()
(同步重绘)。 - 窗口事件如resize、expose、paint等。
- 它是部件级别的,独立于其他部件。
- 由Qt的事件循环自动调用,通常在以下情况:
-
paint:
- 由
QGraphicsView
在渲染整个场景时调用(例如,当视图调用drawItems()
时)。 - 调用时机:
- 场景更新(如项移动、添加/移除项)。
- 视图重绘(类似
paintEvent
,但在场景级别)。
- 它是场景级别的,Qt会遍历场景中的所有项,调用它们的
paint
,并应用变换、裁剪等优化。
- 由
区别:paintEvent
更像"部件自绘",而paint
是"场景渲染的一部分",后者支持批量优化(如只绘制可见项)。
4.5. 实现方式和代码示例
4.5.1. QWidget paintEvent 示例
#include <QWidget>
#include <QPainter>
#include <QPaintEvent>class CustomWidget : public QWidget {
public:CustomWidget(QWidget *parent = nullptr) : QWidget(parent) {}protected:void paintEvent(QPaintEvent *event) override {QPainter painter(this); // 创建画家,绑定到this部件painter.setRenderHint(QPainter::Antialiasing); // 抗锯齿// 只绘制事件指定的区域以优化QRect rect = event->rect();painter.fillRect(rect, Qt::white); // 背景// 绘制一个红色矩形painter.setPen(Qt::red);painter.drawRect(10, 10, width() - 20, height() - 20);}
};// 使用示例(在main中)
int main(int argc, char *argv[]) {QApplication app(argc, argv);CustomWidget widget;widget.resize(200, 200);widget.show();return app.exec();
}
4.5.2. QGraphicsItem paint 示例
#include <QGraphicsItem>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QApplication>class CustomGraphicsItem : public QGraphicsItem {
public:CustomGraphicsItem() {setFlag(QGraphicsItem::ItemIsMovable); // 可移动}QRectF boundingRect() const override {return QRectF(0, 0, 100, 100); // 定义项的边界矩形(必须实现)}void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override {Q_UNUSED(widget); // 通常忽略widgetpainter->setRenderHint(QPainter::Antialiasing);// 使用option优化:只绘制暴露区域QRectF exposed = option->exposedRect;painter->fillRect(exposed, Qt::white); // 背景// 绘制一个红色矩形(在项局部坐标系)painter->setPen(Qt::red);painter->drawRect(boundingRect().adjusted(10, 10, -10, -10));// 如果项被选中,绘制高亮(使用option的状态)if (option->state & QStyle::State_Selected) {painter->setPen(Qt::blue);painter->drawRect(boundingRect());}}
};// 使用示例(在main中)
int main(int argc, char *argv[]) {QApplication app(argc, argv);QGraphicsScene scene;CustomGraphicsItem *item = new CustomGraphicsItem();scene.addItem(item);QGraphicsView view(&scene);view.resize(200, 200);view.show();return app.exec();
}
代码区别:
- 在
paintEvent
中,你需要创建QPainter
并处理整个部件。 - 在
paint
中,QPainter
已提供,你必须实现boundingRect()
来定义项的边界(用于碰撞和渲染优化),并可利用option
处理状态(如选中)。 QGraphicsItem
需要与QGraphicsScene
和QGraphicsView
结合使用,而QWidget
可以独立。
4.6. 性能和适用场景
-
paintEvent:
- 适合简单UI(如按钮、面板),性能依赖于部件数量。大量重叠部件可能导致低效重绘。
- 优化:使用
event->rect()
避免绘制整个区域。
-
paint:
- 适合复杂图形(如游戏、图表、动画),Graphics View有内置优化(如索引、裁剪、变换缓存),处理数千项时更高效。
- 优化:使用
option->exposedRect
和boundingRect()
减少不必要绘制;支持OpenGL渲染加速。
区别:对于高性能图形,QGraphicsItem::paint
更优;对于标准UI,QWidget::paintEvent
更直接。
4.7. 优缺点总结
- 相似点:两者都使用
QPainter
绘制,支持相同绘图API(如drawRect、drawText)。 - QWidget::paintEvent 的优点:简单、直接集成到UI;缺点:不适合复杂变换或大量元素。
- QGraphicsItem::paint 的优点:支持高级功能(如动画、组、效果);缺点:必须实现更多方法(如
boundingRect
),学习曲线稍陡。 - 选择建议:如果构建传统窗口UI,用
QWidget
;如果需要可缩放/可变换的图形场景,用QGraphicsItem
。Qt允许混合使用(如在QGraphicsView
中嵌入QWidget
)。
5. 自定义 QGraphicsRectItem
QGraphicsRectItem
是矩形专用类,继承 QGraphicsItem
,内置矩形管理(如 rect()
、setRect()
)。
5.1. 基础模板
#include <QGraphicsRectItem>
#include <QPen>
#include <QBrush>
#include <QGraphicsSceneMouseEvent>class MyRectItem : public QGraphicsRectItem
{
public:// 构造函数MyRectItem(const QRectF &rect) : QGraphicsRectItem(rect) {setFlag(QGraphicsItem::ItemIsSelectable, true); // 可选中setFlag(QGraphicsItem::ItemIsMovable, true); // 可移动}// 重写 paint 方法,实现自定义绘制void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override{// 1. 绘制矩形if (isSelected())painter->setPen(QPen(Qt::red, 2)); // 选中时红色边框elsepainter->setPen(QPen(Qt::black, 1));painter->setBrush(QBrush(Qt::cyan));painter->drawRect(rect());// 2. 可自定义其他内容painter->setPen(Qt::blue);painter->drawText(rect().center(), "RectItem");}// 可选:自定义交互void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override{// 双击变色setBrush(QBrush(Qt::yellow));update();QGraphicsRectItem::mouseDoubleClickEvent(event); // 保持基类行为}
};
5.2. 使用示例
int main(int argc, char *argv[]) {QApplication app(argc, argv);QGraphicsScene scene(0, 0, 400, 300);MyRectItem *rectItem = new MyRectItem(QRectF(50, 50, 120, 80));scene.addItem(rectItem);QGraphicsView view(&scene);view.show();return app.exec();
}
5.3. 常用 Flags
ItemIsMovable
:可拖动。ItemIsSelectable
:可选中。ItemSendsGeometryChanges
:几何变化通知。
5.4. 常见扩展
- 变形/缩放/旋转:用
setScale()
、setRotation()
或重写事件。 - 外观自定义:在
paint()
根据状态绘制。 - 交互提示:重写
hoverEnterEvent
/hoverLeaveEvent
。
6. 自定义 QGraphicsItem vs QGraphicsRectItem 对比
对比项 | 自定义 QGraphicsItem | 自定义 QGraphicsRectItem |
---|---|---|
继承基类 | QGraphicsItem | QGraphicsRectItem (继承 QGraphicsItem) |
适合场景 | 任意形状(如多边形、圆) | 矩形形状(如块、框选) |
边界定义 | 重写 boundingRect() | 构造函数指定矩形 |
绘制方法 | 重写 paint() ,全实现 | 可重写 paint() ,复用父类 |
矩形属性 | 自行维护成员变量 | 内置 rect() 、setRect() |
几何变换 | 自行实现或调用基类 | 继承支持 |
交互扩展 | 全自定义事件 | 继承父类事件,可扩展 |
使用便捷性 | 灵活但代码多 | 易用,适合矩形需求 |
性能 | 取决于自定义 | 内置优化,适合大量矩形 |
例子 | 自定义图标、曲线 | 选择框、色块、条状图 |
6.1. 说明
QGraphicsItem
:全自定义,像白纸,从零定义边界、绘制、属性。适合非标准形状。QGraphicsRectItem
:预制矩形模板,复用 Qt 逻辑,专注扩展。适合矩形相关。
6.2. QGraphicsItem 示例
#include <QGraphicsItem>
#include <QPainter>
#include <QStyleOptionGraphicsItem>class MyCustomItem : public QGraphicsItem {
private:QRectF m_rect; // 自己维护矩形数据public:MyCustomItem(QRectF rect) : m_rect(rect) {setFlag(QGraphicsItem::ItemIsSelectable, true); // 手动设置选中}// 必须:定义边界(包含所有绘制内容)QRectF boundingRect() const override {return m_rect; // 用自己的 rect}// 必须:全自定义绘制void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override {Q_UNUSED(option); Q_UNUSED(widget); // 忽略参数if (isSelected()) {painter->setPen(QPen(Qt::red, 2)); // 选中高亮,自行判断} else {painter->setPen(QPen(Qt::black, 1));}painter->setBrush(Qt::blue);painter->drawRect(m_rect); // 手动绘制矩形// 可加文字等,自行实现painter->drawText(m_rect.center(), "Custom Item");}// 如果要改大小,自行加方法void setRect(const QRectF &rect) { m_rect = rect; update(); }
};
6.3. QGraphicsRectItem 示例
#include <QGraphicsRectItem>
#include <QPainter>
#include <QStyleOptionGraphicsItem>class MyRectItem : public QGraphicsRectItem {
public:MyRectItem(QRectF rect) : QGraphicsRectItem(rect) { // 构造函数直接传 rect,内置管理setFlag(QGraphicsItem::ItemIsSelectable, true); // 继承设置}// 可选:扩展绘制(父类已有 drawRect,可覆盖加内容)void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override {// 调用父类绘制矩形(复用!)QGraphicsRectItem::paint(painter, option, widget);// 扩展:加高亮和文字if (isSelected()) {painter->setPen(QPen(Qt::red, 2)); // 覆盖边框painter->drawRect(rect()); // 用内置 rect()}painter->setPen(Qt::white);painter->drawText(rect().center(), "Rect Item"); // 内置 center()}// 大小改用内置// 无需额外方法,setRect() 已继承
};
6.4. 代码对比要点
- QGraphicsItem:需私有机 rect 变量、
boundingRect()
返回它、手动drawRect(m_rect)
。改大小需自写 setter。 - QGraphicsRectItem:构造函数传 rect 就行、
paint()
可调用父类复用绘制、用rect()
直接访问。改大小用setRect()
无缝。 - 共同:都用
paint()
绘制,都支持 flag(如选中)。
6.5. 使用场景对比
两者使用相同(加到 QGraphicsScene),但 QGraphicsRectItem 更省事:
// 通用使用
QGraphicsScene scene(0, 0, 400, 300);
MyCustomItem *custom = new MyCustomItem(QRectF(50, 50, 100, 100)); // 传 rect
// 或 MyRectItem *rect = new MyRectItem(QRectF(50, 50, 100, 100));
scene.addItem(custom); // 或 rect
QGraphicsView view(&scene); view.show();
6.6. 优缺点对比
维度 | QGraphicsItem (全自定义) | QGraphicsRectItem (矩形扩展) |
---|---|---|
灵活性 | 最高:任意形状(如圆、多边形、路径) | 中等:限于矩形,但易扩展(如渐变矩形) |
代码量 | 多:边界、属性、绘制全写 | 少:复用父类,专注业务逻辑 |
维护性 | 低:自己管一切,易出错(如边界漏内容) | 高:Qt 管矩形细节,少 bug |
性能 | 好(自定义优化),但需手动 | 更好(内置形状优化,如碰撞检测快) |
缺点 | 起步陡,适合专家 | 不适合非矩形(如想画圆,得用 QGraphicsEllipseItem) |
6.7. 适用场景区别
-
选 QGraphicsItem:
- 需要非标准形状:如自定义图标、心形、曲线图、游戏精灵。
- 完全控制:如 3D 投影或复杂路径绘制。
- 示例:图形编辑器中的自由绘图工具。
-
选 QGraphicsRectItem:
- 矩形相关:进度条、按钮块、网格单元、选择框、色块。
- 快速原型:UI 面板、数据可视化矩形(如柱状图条)。
- 示例:流程图节点、地图区域。
选择建议:先问“这是矩形吗?”如果是,用 QGraphicsRectItem(简单);否则,用 QGraphicsItem(强大)。