При зуме изображения фигуры по клику мыши ставятся в неправильном месте

Привожу в пример небольшое приложение. В нем выводится изображение, на котором нужно отрисовывать фигуры. Если не приближать изображение, то все норм. Но при увеличении изображения фигура ставится не там где надо.

В данном примере по клику на изображении ставится точка. Если не менять зум, то всё ок. А если приближать, то точка ставится не там, где курсор мыши, а дальше. Не могу понять, как это исправить. Так же прилагаю изображение 512х512. Масштаб меняется по колёсику мыши.

UI_test.py

from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtCore import Qt
from random import randint

class Ui_Form(object):
def setupUi(self, Form):
    Form.resize(1300, 700)
    self.layout = QtWidgets.QHBoxLayout()
    self.layout.setContentsMargins(0, 0, 0, 0)
    self.listWidget = QtWidgets.QListWidget()
    self.layout.addWidget(self.listWidget)
    self.stackedWidget = QtWidgets.QStackedWidget()
    self.layout.addWidget(self.stackedWidget)
    self.listWidget.currentRowChanged.connect(
        self.stackedWidget.setCurrentIndex)

    item1 = QtWidgets.QListWidgetItem(QtGui.QIcon('icons/settings.png'),'CamSettings', self.listWidget)
    item2 = QtWidgets.QListWidgetItem(QtGui.QIcon('icons/explore.png'),'Explore', self.listWidget)

    item1.setSizeHint(QtCore.QSize(10, 60))
    item2.setSizeHint(QtCore.QSize(10, 60))

    item1.setTextAlignment(QtCore.Qt.AlignCenter)
    item2.setTextAlignment(QtCore.Qt.AlignCenter)

    label1 = QtWidgets.QLabel('Это страница 1')
    label2= QtWidgets.QLabel('Это страница 2')
    label1.setAlignment(QtCore.Qt.AlignCenter)
    label2.setAlignment(QtCore.Qt.AlignCenter)
    label1.setStyleSheet('background: rgb(%d, %d, %d); margin: 50px;' % (
        randint(0, 255), randint(0, 255), randint(0, 255)))
    label2.setStyleSheet('background: rgb(%d, %d, %d); margin: 50px;' % (
        randint(0, 255), randint(0, 255), randint(0, 255)))

    self.img_rgb = QtWidgets.QGraphicsScene()
    self.view_rgb = QtWidgets.QGraphicsView()
    self.view_rgb.setScene(self.img_rgb )
    pixmap_rgb = QtGui.QPixmap()
    self.img_rgb.addPixmap('pic.png')
    border_style_rgb = f'border-style: solid; border-width: 2px;  background-color:#757575;'
    self.view_rgb.setStyleSheet(border_style_rgb)
    self.view_rgb.setFixedSize(520,520)
    self.view_rgb.mousePressEvent = Form.press_event
    #self.view_rgb.mouseMoveEvent = Form.move_event
    #self.view_rgb.mouseReleaseEvent = Form.release_event
    self.view_rgb.wheelEvent = Form.wheel_event

    first_panel_left = QtWidgets.QVBoxLayout()
    first_panel_left.setAlignment(Qt.AlignTop)
    first_panel_frame_left = QtWidgets.QFrame()
    first_panel_frame_left.setMinimumWidth(200)
    first_panel_frame_left.setLayout(first_panel_left)
    first_panel_right = QtWidgets.QVBoxLayout()
    first_panel_right.addWidget(self.view_rgb)
    first_panel_right.addStretch()
    first_panel_frame_right = QtWidgets.QFrame()
    first_panel_frame_right.setLayout(first_panel_right)
    main_first_box = QtWidgets.QHBoxLayout()
    main_first_box.addWidget(first_panel_frame_left)
    main_first_box.addWidget(first_panel_frame_right)
    first_container = QtWidgets.QWidget()
    first_container.setLayout(main_first_box)
    self.stackedWidget.addWidget(first_container)
    self.stackedWidget.addWidget(label2)
    Form.setLayout(self.layout)

app.py

import sys
from PySide2 import QtWidgets
from UI_test import Ui_Form
from PySide2 import QtWidgets, QtGui, QtCore
from tools import DotPainter

class App(QtWidgets.QWidget):
def __init__(self, parent = None):
    QtWidgets.QWidget.__init__(self, parent)
    self.ui = Ui_Form()
    self.ui.setupUi(self)
    self._zoom = 0

def press_event(self, event):
    self.clickPos = event.pos()
    self.clickBtn= event.button()
    print(self.clickPos)
    if self.clickBtn & QtCore.Qt.LeftButton:
        self.pointItem=DotPainter(self.ui.img_rgb,self.clickPos)

def fitInView(self):
    rect = QtCore.QRectF(0.0, 0.0, 512.0, 512.0)
    if not rect.isNull():
        self.ui.view_rgb.setSceneRect(rect)
        unity = self.ui.view_rgb.transform().mapRect(QtCore.QRectF(0, 0, 1, 1))
        self.ui.view_rgb.scale(1 / unity.width(), 1 / unity.height())
        viewrect = self.ui.view_rgb.viewport().rect()
        scenerect = self.ui.view_rgb.transform().mapRect(rect)
        factor = min(viewrect.width() / scenerect.width(),
                    viewrect.height() / scenerect.height())
        self.ui.view_rgb.scale(factor, factor)
        self._zoom = 0

def wheel_event(self,event):
    if event.angleDelta().y() > 0:
        factor = 1.25
        self._zoom += 1
    else:
        factor = 0.8
        self._zoom -= 1
    if self._zoom > 0:
        self.ui.view_rgb.scale(factor, factor)
    elif self._zoom == 0:
        self.fitInView()
    else:
        self._zoom = 0


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = App()
    window.show()
    sys.exit(app.exec_())

tools.py

from PySide2.QtCore import Qt,QRectF,QPointF,QSizeF
from PySide2.QtGui import QPen,QColor,QBrush,QPolygonF
from PySide2 import QtWidgets, QtGui, QtCore


class DotPainter(object):
#класс для рисования точки
def __init__(self, canvas, start):
    self.start = start
    self.canvas = canvas
    self.point=QRectF()
    self.width = self.point.width()
    self.height = self.point.height()
    self.PointF = QPointF(float(start.x()), float(start.y()))
    self.point.setTopLeft(self.PointF)
    self.point.setSize(QSizeF(8, 8))
    self.linePen = QPen(QtGui.QColor(255,0,0), 2)
    self.areaBrush = QBrush(QColor(255,0,0))
    self.pointItem=self.canvas.addRect(self.point,
                                          self.linePen,self.areaBrush)
def mouseReleaseEvent(self, event):
    #функция события мыши для получения размеров точки
    self.width = self.point.width()
    self.height = self.point.height()

введите сюда описание изображения


Ответы (1 шт):

Автор решения: Spatz

Вам нужно либо преобразовывать позицию клика в позицию сцены

    def press_event(self, event):
        self.clickPos = event.pos()
        self.clickBtn = event.button()
        scenePos = self.ui.view_rgb.mapToScene(self.clickPos)
        if self.clickBtn & QtCore.Qt.LeftButton:
            self.pointItem = DotPainter(self.ui.img_rgb, scenePos)

либо привязывать обработчик кликов к самой сцене (а не вьюхе) и извлекать позицию методом scenePos (данный обработчик получает событие типа QGraphicsSceneMouseEvent)

  self.img_rgb.mousePressEvent = Form.scene_press_event
    def scene_press_event(self, event):
        self.clickBtn = event.button()
        if self.clickBtn & QtCore.Qt.LeftButton:
            DotPainter(self.ui.img_rgb, event.scenePos())
→ Ссылка