You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QGraphicsObject中mouseMove与mousePress事件鼠标位置不一致问题咨询

解决QGraphicsObject缩放后鼠标事件位置不一致的问题

嘿,这个缩放导致鼠标事件位置错位的问题我太熟悉了!咱们直接说结论:确实需要根据缩放更新boundingRect,而且还要配合正确的坐标转换和Qt的几何更新机制,具体操作如下:

核心原因

未缩放时,场景坐标和你的TicTacToe item的局部坐标是1:1映射的,所以mousePressEvent和mouseMoveEvent里的位置能对上;但缩放后,item的实际显示尺寸变了,如果boundingRect没同步更新,Qt会用旧的边界来判断事件是否属于这个item,再加上你如果直接用场景坐标而不转成item局部坐标,就会出现位置差异。

具体操作步骤

1. 维护缩放因子变量

在你的TicTacToe类里添加一个私有变量来记录当前缩放比例:

class TicTacToe(QGraphicsObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._scale = 1.0  # 初始缩放因子为1.0
        # 其他初始化代码...

2. 重写boundingRect()方法,基于缩放因子返回正确边界

确保boundingRect始终匹配item缩放后的实际尺寸:

def boundingRect(self):
    # 假设你原本的item基础尺寸是100x100,根据缩放因子调整
    original_width = 100
    original_height = 100
    return QRectF(0, 0, original_width * self._scale, original_height * self._scale)

3. 执行缩放时更新因子并通知Qt几何变化

当你对item进行缩放操作时,一定要先调用prepareGeometryChange()(告诉Qt你的item几何形状要更新了),再修改缩放因子:

def set_scale(self, new_scale):
    self.prepareGeometryChange()  # 必须先调用这个!否则Qt不会重新计算事件区域
    self._scale = new_scale
    self.update()  # 触发重绘,让缩放效果生效

4. 鼠标事件中转换为item局部坐标

在mousePressEvent和mouseMoveEvent里,把场景坐标转换为item自身的局部坐标,这样不管缩放多少,拿到的都是item坐标系下的位置:

def mousePressEvent(self, event):
    # 把场景坐标转成item局部坐标
    local_pos = self.mapFromScene(event.pos())
    print("鼠标点击局部位置:", local_pos)
    # 你的其他处理逻辑...
    super().mousePressEvent(event)

def mouseMoveEvent(self, event):
    local_pos = self.mapFromScene(event.pos())
    print("鼠标移动局部位置:", local_pos)
    # 你的其他处理逻辑...
    super().mouseMoveEvent(event)

完整修改后的代码片段

#!/usr/bin/env python
from PyQt5.QtCore import QRectF
from PyQt5.QtGui import QPainter, QPixmap
from PyQt5.QtWidgets import QMainWindow, QApplication, QGraphicsObject, QGraphicsView, QGraphicsScene

class TicTacToe(QGraphicsObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._scale = 1.0
        # 替换成你实际使用的资源或基础尺寸
        self._base_width = 100
        self._base_height = 100
        self._pixmap = QPixmap("tic_tac_toe.png")  # 可选:如果用图片绘制

    def boundingRect(self):
        return QRectF(0, 0, self._base_width * self._scale, self._base_height * self._scale)

    def paint(self, painter, option, widget):
        painter.scale(self._scale, self._scale)
        if not self._pixmap.isNull():
            painter.drawPixmap(0, 0, self._pixmap)
        else:
            # 无图片时绘制基础矩形
            painter.drawRect(0, 0, self._base_width, self._base_height)

    def set_scale(self, new_scale):
        self.prepareGeometryChange()
        self._scale = new_scale
        self.update()

    def mousePressEvent(self, event):
        local_pos = self.mapFromScene(event.pos())
        print(f"点击局部坐标:{local_pos.x()}, {local_pos.y()}")
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        local_pos = self.mapFromScene(event.pos())
        print(f"移动局部坐标:{local_pos.x()}, {local_pos.y()}")
        super().mouseMoveEvent(event)

# 测试用主窗口
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.scene = QGraphicsScene()
        self.view = QGraphicsView(self.scene)
        self.setCentralWidget(self.view)
        
        self.tic_tac_toe = TicTacToe()
        self.scene.addItem(self.tic_tac_toe)
        
        # 测试缩放:比如放大到1.5倍
        self.tic_tac_toe.set_scale(1.5)

if __name__ == "__main__":
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

这样操作后,不管你怎么缩放,鼠标事件的位置都会和item的实际显示区域匹配,不会再出现错位的问题啦~

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:15:09