You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PyQt5中QGraphicsView无法触发mouseMove与mouseRelease事件咨询

解决QGraphicsView无法触发mouseMoveEvent和mouseReleaseEvent的问题

我来帮你搞定这个问题!你当前代码的核心问题是鼠标事件被QGraphicsView控件拦截了——你把鼠标事件处理逻辑写在了主窗口MainScreen类里,但实际上你的鼠标操作对象是graphicsView这个子控件,主窗口根本接收不到这些事件,自然mouseMoveEventmouseReleaseEvent不会被触发。

核心解决方案:自定义QGraphicsView子类

我们需要创建一个继承自QGraphicsView的自定义类,把鼠标事件的处理逻辑移到这个类里,因为只有它能直接捕获到自身上的鼠标操作。

修改后的完整代码

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PIL import Image
from PyQt5 import uic

QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
IS_RESULT = False
CROP_UI = uic.loadUiType("Image_crop_screen.ui")[0]
BRING_IN_IMG_ROUTE = "C:/Users/yoon/Desktop/test/test.jpg"

class CustomGraphicsView(QGraphicsView):
    def __init__(self, parent=None):
        super().__init__(parent)
        # 初始化绘图参数
        self.pencolor = QColor(240, 240, 240)
        self.brushcolor = QColor(255, 255, 255, 0)
        self.start = QPoint()
        self.end = QPoint()
        self.items = []
        # 创建场景并关联到视图
        self.scene = QGraphicsScene(self)
        self.setScene(self.scene)
        # 开启交互和鼠标跟踪
        self.setInteractive(True)
        self.setMouseTracking(True)

    def setImage(self, pixmap):
        # 添加图片到场景,并设置场景范围匹配图片
        self.img = QGraphicsPixmapItem(pixmap)
        self.scene.addItem(self.img)
        self.scene.setSceneRect(pixmap.rect())

    def mousePressEvent(self, e):
        if e.button() == Qt.LeftButton:
            # 记录起始点(视图坐标)
            self.start = e.pos()
            self.end = e.pos()
            print("鼠标按下:", Qt.LeftButton, e.buttons(), e)
        # 调用父类事件,保留原有交互逻辑
        super().mousePressEvent(e)

    def mouseMoveEvent(self, e):
        # 仅在左键按下时处理移动事件
        if e.buttons() & Qt.LeftButton:
            self.end = e.pos()
            pen = QPen(self.pencolor)
            brush = QBrush(self.brushcolor)
            pen.setWidth(3)
            # 删除上一次绘制的矩形,避免残留
            if len(self.items) > 0:
                self.scene.removeItem(self.items[-1])
                del self.items[-1]
            # 关键:将视图坐标转换为场景坐标,确保矩形和图片位置对应
            start_scene = self.mapToScene(self.start)
            end_scene = self.mapToScene(self.end)
            rect = QRectF(start_scene, end_scene)
            self.items.append(self.scene.addRect(rect, pen, brush))
        super().mouseMoveEvent(e)

    def mouseReleaseEvent(self, e):
        print("鼠标释放触发")
        if e.button() == Qt.LeftButton:
            print("左键释放处理")
            pen = QPen(self.pencolor)
            brush = QBrush(self.brushcolor)
            self.items.clear()
            # 再次转换坐标,获取最终裁剪区域
            start_scene = self.mapToScene(self.start)
            end_scene = self.mapToScene(self.end)
            rect = QRectF(start_scene, end_scene)
            self.scene.addRect(rect, pen, brush)
            print(f"裁剪区域坐标: ({start_scene.x()}, {start_scene.y()}), ({end_scene.x()}, {end_scene.y()})")
            area = (start_scene.x(), start_scene.y(), end_scene.x(), end_scene.y())
            # 这里可以添加裁剪图片的逻辑,比如用PIL处理
        super().mouseReleaseEvent(e)

class MainScreen(QMainWindow, CROP_UI):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        # 替换UI中的默认QGraphicsView为自定义视图
        layout = self.graphicsView.parent().layout()
        if layout:
            layout.removeWidget(self.graphicsView)
            self.graphicsView.deleteLater()
        self.graphicsView = CustomGraphicsView(self)
        layout.addWidget(self.graphicsView)
        # 设置要裁剪的图片
        self.graphicsView.setImage(QPixmap(BRING_IN_IMG_ROUTE))
        # 窗口尺寸设置
        _WIDTH_ADD = 25
        _HEIGHT_ADD = 25
        self.setGeometry(0, 0, 640 + _WIDTH_ADD, 500 + _HEIGHT_ADD)

    def moveEvent(self, e):
        # 保留原有的窗口移动时的场景调整逻辑(如果需要)
        super().moveEvent(e)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainScreen()
    w.show()
    sys.exit(app.exec_())

关键细节说明

  1. 事件捕获逻辑:鼠标事件只会发送给当前鼠标所在的控件,所以必须在QGraphicsView子类里重写事件处理函数,才能捕获到视图上的鼠标操作。
  2. 坐标转换e.pos()是相对于视图的局部坐标,需要用mapToScene()转换为场景坐标,这样绘制的矩形才能和图片的实际位置对应,避免出现偏移。
  3. 父类事件调用:每个重写的鼠标事件最后都要调用super()方法,确保QGraphicsView原有的交互功能(比如拖动图片、缩放)不受影响。
  4. 鼠标跟踪setMouseTracking(True)确保视图能持续接收鼠标移动事件,虽然你只需要左键按下时的移动,但开启这个属性能避免一些潜在的事件丢失问题。

这样修改后,你的图片裁剪工具就能正常触发所有鼠标事件,并且正确绘制裁剪区域了!

内容的提问来源于stack exchange,提问作者윤종윤

火山引擎 最新活动