Pyside鼠标
键盘+鼠标左键点击
# 基础代码
from PySide6.QtCore import QEvent, QObject, Qt
from PySide6.QtWidgets import QApplication, QWidget
app = QApplication([])
w = QWidget()
# 鼠标事件中检查键盘状态
w.mousePressEvent = lambda e: (print('Ctrl+左键' if e.modifiers() & Qt.ControlModifier and e.button() == Qt.LeftButton else '普通左键'))
# 写filter也行
class FilterShell(QObject):
def eventFilter(self, obj, ev):
if ev.type() == QEvent.MouseButtonPress and ev.modifiers() & Qt.ControlModifier:
print('过滤器截到 Ctrl+点击')
return False # true = 吃掉
return False
shell = FilterShell()
w.installEventFilter(shell)
w.show()
app.exec()
如果是view-scene-item体系中, 要在item上做快捷键+鼠标点击
- 每个item注册mousepressevent是比较简单的方法
- fileter判断obj会相当麻烦, 因为, view-scene-item架构中fileter不会像widget那样下发到目标widget.
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QGraphicsScene, QGraphicsTextItem, QGraphicsView
app = QApplication([])
scene = QGraphicsScene()
view = QGraphicsView(scene)
# --------------- 关键代码 ---------------
item = QGraphicsTextItem('点击我也可编辑')
item.setTextInteractionFlags(Qt.TextInteractionFlag.TextEditable) # 允许编辑
origin_press = item.mousePressEvent # 先保存原来的入口
def multi_click(self, ev):
if ev.modifiers() & Qt.AltModifier and ev.button() == Qt.LeftButton:
print('Alt+左键 触发')
ev.accept() # 吃掉,不再往下传
return
# 普通左键,交给原来的编辑逻辑
origin_press(ev)
item.mousePressEvent = lambda e: multi_click(item, e)
# ----------------------------------------
scene.addItem(item)
view.show()
app.exec()
- 特别注意:
- 有效写法: item = QGraphicsTextItem(‘点击我也可编辑’)
- 失效写法: r = scene.addText(“方块”, QFont(“Arial”, 12))
- 原因: scene.addText() 内部提前 accept 掉了事件,把编辑逻辑“写死”了一次,
再重写 mousePressEvent 时它已经 提前退出,于是看起来“失效”。
右键菜单(view-scene-item体系)
'''
1. view-scene的右键, 全局展示相关, 缩放得等
2. textitem的右键, 展开, 搜索, 编辑, 剪切等等.
'''
from PySide6.QtCore import Qt
from PySide6.QtGui import QTransform
from PySide6.QtWidgets import QApplication, QGraphicsScene, QGraphicsTextItem, QGraphicsView, QMenu
app = QApplication([])
scene = QGraphicsScene()
view = QGraphicsView(scene)
item = QGraphicsTextItem("右键我")
item.setTextInteractionFlags(Qt.TextEditable)
# 1. 先保存原来的入口
old_press = item.mousePressEvent
## 2. 右键拦截:吃掉事件,阻止父类自动编辑
# item.mousePressEvent = lambda e: (e.accept() if e.button() == Qt.RightButton else old_press(e))
# ---- 关键 ----
def pop_menu(self, event):
menu = QMenu()
edit_act = menu.addAction("编辑")
del_act = menu.addAction("删除")
edit_act.triggered.connect(lambda: print("开始编辑"))
del_act.triggered.connect(lambda: scene.removeItem(item)) # 真正的删除
action = menu.exec(event.screenPos())
print("选中了:", action.text() if action else "没选")
item.contextMenuEvent = lambda e: pop_menu(item, e)
# ---------- 背景菜单 ----------
def scene_menu(self, event):
it = self.itemAt(event.scenePos(), QTransform())
if it: # 点中 item → 不处理,事件继续飘
it.contextMenuEvent(event)
return
menu = QMenu()
menu.addAction("全局放大").triggered.connect(lambda: view.scale(1.2, 1.2))
menu.addAction("全局缩小").triggered.connect(lambda: view.scale(1 / 1.2, 1 / 1.2))
menu.exec(event.screenPos()) # Scene 坐标已转屏幕坐标
event.accept() # 空白处:我处理完了
scene.contextMenuEvent = lambda e: scene_menu(scene, e)
scene.addItem(item)
view.show()
app.exec()
- 关键点, 只要scene拿了右键菜单, 事件就死活不往下传递了. 必须在scene的事件里面调用item的事件才行.
滚轮/捏合/扩张
# -*- coding: utf-8 -*-
import sys
from PySide6.QtCore import QEvent, QPointF, Qt
from PySide6.QtWidgets import QApplication, QGraphicsRectItem, QGraphicsScene, QGraphicsView
app = QApplication(sys.argv)
# 1. 创建场景并放点内容
scene = QGraphicsScene(-200, -200, 400, 400)
scene.addItem(QGraphicsRectItem(-50, -50, 100, 100))
# 2. 创建视图
view = QGraphicsView(scene)
view.setDragMode(QGraphicsView.ScrollHandDrag) # 关键代码, 允许view被整体拖动
view.resize(800, 600)
# 3. 注册 pinch 手势
view.grabGesture(Qt.PinchGesture)
# 4. 公共缩放函数
def zoom_at(v: QGraphicsView, pos: QPointF, factor: float):
target = v.mapToScene(pos.toPoint())
v.scale(factor, factor)
delta = v.mapToScene(pos.toPoint()) - target
v.translate(delta.x(), delta.y())
# 5. 滚轮事件
def wheel_event(ev):
if ev.modifiers() & Qt.AltModifier:
factor = 1.15 if ev.angleDelta().y() > 0 else 0.87
zoom_at(view, ev.position(), factor)
ev.accept()
else:
QGraphicsView.wheelEvent(view, ev) # 继续走默认处理
view.wheelEvent = wheel_event # 把成员函数替换掉
# 6. 手势事件
def event_handler(ev: QEvent):
if ev.type() == QEvent.Type.Gesture:
pinch = ev.gesture(Qt.PinchGesture)
if pinch and pinch.changeFlags():
zoom_at(view, pinch.centerPoint(), pinch.scaleFactor())
return True
return QGraphicsView.event(view, ev) # 继续走默认处理
view.event = event_handler
# 7. 跑起来
view.show()
sys.exit(app.exec())