PyQt6/PySide6 的 QPropertyAnimation 类
一、概述
QGraphicsView 和 QGraphicsScene 是 Qt 图形视图框架的核心类,用于构建高性能、可交互的 2D 图形界面。
核心分工:
- QGraphicsScene:管理场景中的图形项(
QGraphicsItem
),处理事件和坐标系统。 - QGraphicsView:作为观察场景的视口,提供缩放、平移、旋转等视图变换功能。
适用场景:
- 复杂绘图(如 CAD 工具)
- 游戏开发(2D 场景)
- 数据可视化(图表、流程图)
- 交互式图形界面(可拖拽、编辑的组件)
二、核心组件与关系
-
组件层级
QGraphicsView (视图) └── QGraphicsScene (场景) └── QGraphicsItem (图形项:矩形、椭圆、文本、自定义项等)
-
坐标系差异
- 场景坐标:场景的全局坐标系(原点在场景中心或自定义位置)。
- 视图坐标:视图窗口的坐标系(原点在左上角)。
- 项坐标:每个图形项自身的局部坐标系。
三、基础使用步骤
-
创建场景与视图
from PyQt6.QtWidgets import QGraphicsView, QGraphicsScene, QApplication from PyQt6.QtCore import Qt scene = QGraphicsScene() # 创建场景 view = QGraphicsView(scene) # 创建视图并绑定场景 view.setRenderHint(QPainter.RenderHint.Antialiasing) # 抗锯齿 view.resize(800, 600) view.show()
-
添加图形项到场景
# 添加矩形(位置、大小、颜色) rect = scene.addRect(0, 0, 100, 50, Qt.GlobalColor.red, Qt.GlobalColor.blue) # 添加文本 text = scene.addText("Hello Graphics", QFont("Arial", 12)) text.setPos(50, 50) # 添加椭圆 ellipse = scene.addEllipse(200, 100, 80, 60, Qt.GlobalColor.green)
四、核心功能与实战案例
-
交互式图形项(拖拽、旋转)
class MovableRect(QGraphicsRectItem): def __init__(self, x, y, w, h): super().__init__(x, y, w, h) self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable) # 允许拖拽 self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable) # 允许选中 self.setBrush(Qt.GlobalColor.cyan) # 添加可移动矩形到场景 movable_rect = MovableRect(300, 200, 80, 40) scene.addItem(movable_rect)
-
视图操作(缩放与平移)
# 鼠标滚轮缩放 def wheelEvent(self, event): factor = 1.2 if event.angleDelta().y() > 0 else 0.8 self.scale(factor, factor) # 右键拖拽平移 view.setDragMode(QGraphicsView.DragMode.ScrollHandDrag) # 设置拖拽模式
-
自定义图形项(绘制箭头)
class ArrowItem(QGraphicsItem): def boundingRect(self): return QRectF(-10, -5, 20, 10) # 定义项边界 def paint(self, painter, option, widget): painter.setPen(QPen(Qt.GlobalColor.black, 2)) painter.drawLine(0, 0, 10, 0) # 箭头主体 painter.drawLine(10, 0, 5, -5) # 箭头尖端 painter.drawLine(10, 0, 5, 5) arrow = ArrowItem() arrow.setPos(400, 300) scene.addItem(arrow)
-
动画与图形项结合
# 使用 QPropertyAnimation 移动图形项 from PyQt6.QtCore import QPropertyAnimation anim = QPropertyAnimation(arrow, b"pos") anim.setDuration(2000) anim.setStartValue(QPointF(400, 300)) anim.setEndValue(QPointF(500, 400)) anim.setEasingCurve(QEasingCurve.Type.InOutQuad) anim.start()
五、高级功能
-
碰撞检测
# 检测矩形与其他项的碰撞 colliding_items = rect.collidingItems() for item in colliding_items: item.setBrush(Qt.GlobalColor.yellow) # 高亮碰撞项
-
组合项(QGraphicsItemGroup)
group = QGraphicsItemGroup() group.addToGroup(rect) group.addToGroup(text) group.setRotation(45) # 整体旋转 45 度 scene.addItem(group)
-
场景事件处理
class CustomScene(QGraphicsScene): def mousePressEvent(self, event): if event.button() == Qt.MouseButton.LeftButton: print(f"Scene 点击位置:{event.scenePos()}") super().mousePressEvent(event)
六、注意事项
-
性能优化
- 避免在场景中放置过多项(超过数千个)。
- 使用
QGraphicsItem.ItemClipsToShape
或setCacheMode
优化渲染。
-
坐标转换
- 使用
mapToScene()
和mapFromScene()
在视图、场景、项之间转换坐标。
# 将视图坐标 (100, 200) 转换为场景坐标 scene_pos = view.mapToScene(100, 200)
- 使用
-
内存管理
- 删除图形项时需调用
removeItem()
,避免内存泄漏。
scene.removeItem(rect) del rect # 显式删除对象
- 删除图形项时需调用
七、综合案例:简易绘图工具
class DrawingScene(QGraphicsScene):
def __init__(self):
super().__init__()
self.current_item = None
def mousePressEvent(self, event):
if event.button() == Qt.MouseButton.LeftButton:
self.current_item = QGraphicsEllipseItem()
self.current_item.setRect(event.scenePos().x(),
event.scenePos().y(),
0, 0)
self.addItem(self.current_item)
def mouseMoveEvent(self, event):
if self.current_item:
start_pos = event.buttonDownScenePos(Qt.MouseButton.LeftButton)
current_pos = event.scenePos()
self.current_item.setRect(
start_pos.x(), start_pos.y(),
current_pos.x() - start_pos.x(),
current_pos.y() - start_pos.y()
)
def mouseReleaseEvent(self, event):
self.current_item = None
# 使用示例
app = QApplication([])
scene = DrawingScene()
view = QGraphicsView(scene)
view.show()
app.exec()
八、总结
QGraphicsView 和 QGraphicsScene 为复杂图形应用提供了强大支持,通过组合图形项、处理事件和优化渲染,可实现高度定制化的交互式界面。开发时需重点关注坐标系统、性能管理和用户交互逻辑。