键盘+鼠标左键点击

# 基础代码
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上做快捷键+鼠标点击

  1. 每个item注册mousepressevent是比较简单的方法
  2. 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())