Pyside的mode
pyside的各种…. 太方便了
举例
- 想拖动画布?
setDragMode(ScrollHandDrag)
一行搞定 - 想框选 item?
setDragMode(RubberBandDrag)
也是一行 - 想缩放?
wheelEvent
里scale()
一下就行 - 想捏合?
grabGesture(Qt.PinchGesture)
就能收到原生手势 - item的setTextInteractionFlags
列表
一、View 级(QGraphicsView)
“画布”本身的行为,缩放/平移/手势/对齐一股脑都在这里。
目标 | 一行代码 | 说明 |
---|---|---|
左键拖拽平移 | view.setDragMode(QGraphicsView.ScrollHandDrag) |
左键拖 = 移动场景 |
框选 item | view.setDragMode(QGraphicsView.RubberBandDrag) |
左键拖 = 拉橡皮筋 |
滚轮缩放 | 见下方 wheelEvent 模板 |
以光标为中心 |
两指捏合 | view.grabGesture(Qt.PinchGesture) + event.gesture(...) |
完整代码在隔壁鼠标 |
抗锯齿 | view.setRenderHint(QPainter.Antialiasing) |
|
对齐网格 | view.setAlignment(Qt.AlignLeft \| Qt.AlignTop) |
|
隐藏滚动条 | view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) |
二、Scene 级(QGraphicsScene)
“模型”层,只管逻辑坐标、item 检索、事件分发。
目标 | 一行代码 | 说明 |
---|---|---|
场景矩形 | scene.setSceneRect(-1000, -1000, 2000, 2000) |
无限大默认 |
背景网格 | scene.setBackgroundBrush(QBrush(Qt.gray, Qt.CrossPattern)) |
|
点击选不中? | scene.itemIndexMethod() 默认就是 BspTreeIndex,一般不动 |
|
批量碰撞 | items = scene.items(QPointF(x, y)) |
返回列表,可过滤 type |
视图同步 | view.setScene(scene) |
一对多也允许多个 view 挂同一场景 |
三、Item 级(QGraphicsItem 家族)
真正“会动”的东西,OO 精华最密集。
1. 文本/编辑相关
| 目标 | 一行代码 | 说明 |
| ——– | ——————————————————– | ————————— |
| 文本可选 | item.setTextInteractionFlags(Qt.TextSelectableByMouse)
| 对 QGraphicsTextItem
有效 |
| 文本可改 | item.setTextInteractionFlags(Qt.TextEditable)
| |
| 链接可点 | item.setOpenExternalLinks(True)
| 同样只对 TextItem |
| 字体 | item.setFont(QFont("Arial", 12))
| |
| 换行宽度 | item.setTextWidth(200)
| 0=不自动换行 |
2. 标志位(QGraphicsItem.GraphicsItemFlag)
| 目标 | 一行代码 | 说明 |
| ——– | ——————————————————– | ———————— |
| 可移动 | item.setFlag(QGraphicsItem.ItemIsMovable)
| |
| 可聚焦 | item.setFlag(QGraphicsItem.ItemIsFocusable)
| 否则收不到键盘事件 |
| 可选取 | item.setFlag(QGraphicsItem.ItemIsSelectable)
| 和 RubberBandDrag 联动 |
| 不画边框 | item.setFlag(QGraphicsItem.ItemClipsToShape)
| |
| 忽略缩放 | item.setFlag(QGraphicsItem.ItemIgnoresTransformations)
| 文字标签固定像素大小神器 |
| 缓存加速 | item.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
| |
3. 坐标/变形
| 目标 | 一行代码 | 说明 |
| ———— | ———————————————————— | ————————————– |
| 转场景坐标 | pt_scene = item.mapToScene(item.rect().topLeft())
| |
| 转视图坐标 | pt_view = view.mapFromScene(pt_scene)
| |
| 自身旋转 | item.setRotation(45)
| |
| 自身缩放 | item.setScale(1.5)
| 不影响子级就用 setTransform()
更灵活 |
| 原点移到中心 | item.setTransformOriginPoint(item.boundingRect().center())
| |
四、速用模板(无 class 版)
把下面三坨黏一起就是一个“可滚轮+捏合+拖拽 item”的最小画布:
import sys
from PySide6.QtCore import *
from PySide6.QtWidgets import *
from PySide6.QtGui import *
app = QApplication(sys.argv)
# 1. 场景
scene = QGraphicsScene(-500, -500, 1000, 1000)
# 2. 视图
view = QGraphicsView(scene)
view.setDragMode(QGraphicsView.ScrollHandDrag)
view.grabGesture(Qt.PinchGesture)
view.resize(800, 600)
# 3. 随手放两个 item
text = scene.addText("PySide6\n可编辑文字", QFont("Arial", 20))
text.setTextInteractionFlags(Qt.TextEditorInteraction) # ← 精华一行
rect = scene.addRect(QRectF(-60, -60, 120, 120),
QPen(Qt.black), QBrush(Qt.green))
rect.setFlag(QGraphicsItem.ItemIsMovable) # ← 精华一行
rect.setFlag(QGraphicsItem.ItemIsSelectable)
# 4. 缩放函数(滚轮 & 捏合)
def zoom_at(pos, factor):
anchor = view.mapToScene(pos.toPoint())
view.scale(factor, factor)
delta = view.mapToScene(pos.toPoint()) - anchor
view.translate(delta.x(), delta.y())
view.wheelEvent = lambda ev: (zoom_at(ev.position(), 1.15 if ev.angleDelta().y()>0 else 0.87),
ev.accept())
view.event = lambda ev: (zoom_at(ev.gesture(Qt.PinchGesture).centerPoint().toPoint(),
ev.gesture(Qt.PinchGesture).scaleFactor())
if ev.type()==QEvent.Gesture and ev.gesture(Qt.PinchGesture)
else QGraphicsView.event(view, ev))
view.show()
sys.exit(app.exec())
扩展内容:
- QGraphicsItem 做 自定义形状 + 碰撞检测 → 必须重载
boundingRect()
/paint()
/shape()
- 动画/帧率 → QTimeLine, QPropertyAnimation
- OpenGL 加速 →
QOpenGLWidget
作为 viewport - 多线程场景渲染 → QGraphicsSceneBspTreeIndex 调优参数