es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

La detección de eventos del ratón no es consistente con el QGraphicsItem personalizado en el gráfico de pyqtgraph.

Modifiqué el método de pintura de un objeto pixmap para que siempre se dibuje escalado como un porcentaje de la altura del widget y centrado alrededor de la coordenada x de la posición en la que se ha colocado.

Sin embargo, los objetos resultantes no detectan correctamente cuando se les hace clic.

En mi ejemplo, gran parte del área debajo de roi1 informa “got me” y no puedo encontrar en ningún lugar que informe “got me” en roi2.

import pyqtgraph as pg
from PyQt5 import QtWidgets, QtGui, QtCore
import numpy as np
from PyQt5.QtCore import Qt
import logging

class ScaleInvariantIconItem(QtWidgets.QGraphicsPixmapItem):
    def __init__(self, *args, **kwargs):
        self.id = kwargs.pop("id", "dummy")
        self.count = 0
        super().__init__(*args, **kwargs)
        self.setPixmap(QtWidgets.QLabel().style().standardPixmap(QtWidgets.QStyle.SP_FileDialogStart))
        self.scale_percent = .25
        self._pen = None

    def setPen(self, pen):
        self._pen = pen
        self.update()

    def mousePressEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
        print("got me", self.id, self.count)
        self.count += 1

    def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionGraphicsItem', widget: QtWidgets.QWidget):

        h_scene = self.scene().parent().height()
        h = self.pixmap().height()

        t = painter.transform();
        s = (self.scale_percent*h_scene)/h
        self.setTransformOriginPoint(self.pixmap().width()/2,0)
        painter.save()

        painter.setTransform(QtGui.QTransform(s, t.m12(), t.m13(),
                                              t.m21(), s, t.m23(),
                                              t.m31(), t.m32(), t.m33()))
        painter.translate(-self.pixmap().width() / 2, 0)

        super().paint(painter, option, widget)
        if self._pen:
            painter.setPen(self._pen)
        painter.drawRect(self.pixmap().rect())
        painter.restore()

app = QtWidgets.QApplication([])
pg.setConfigOption('leftButtonPan', False)

g = pg.PlotWidget()

g = pg.PlotWidget()

QtWidgets.QGraphicsRectItem

roi = ScaleInvariantIconItem(id=1)

roi2 = ScaleInvariantIconItem(id=2)
roi2.setPos(10,20)
roi2.setPen(pg.mkPen('g'))

vb = g.plotItem.getViewBox()

vb.setXRange(-20,20)
vb.setYRange(-20,20)
g.addItem(roi)

g.addItem(roi2)

g.addItem(roi2)
g.show()
app.exec_()
Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El problema en este código es que el método paint está escalando y desplazando el pixmap, pero no está actualizando el rectángulo delimitador para reflejar el tamaño y posición escalados del elemento. Como resultado, el área clickeable del elemento permanece en su posición y tamaño original, en lugar de estar correctamente escalada y centrada.

    Para solucionar este problema, el método boundingRect del elemento también debe ser actualizado para reflejar el tamaño y posición escalados del elemento. Esto se puede hacer multiplicando el rectángulo original del pixmap por el factor de escalado y desplazando el rectángulo resultante por la posición escalada del elemento.

    Aquí hay una implementación de ejemplo de los métodos paint y boundingRect actualizados:

    class ScaleInvariantIconItem(QtWidgets.QGraphicsPixmapItem):
        def __init__(self, *args, **kwargs):
            self.id = kwargs.pop("id", "dummy")
            self.count = 0
            super().__init__(*args, **kwargs)
            self.setPixmap(QtWidgets.QLabel().style().standardPixmap(QtWidgets.QStyle.SP_FileDialogStart))
            self.scale_percent = 0.25
            self._pen = None
    
        def setPen(self, pen):
            self._pen = pen
            self.update()
    
        def mousePressEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
            print("got me", self.id, self.count)
            self.count += 1
    
        def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionGraphicsItem', widget: QtWidgets.QWidget):
    
            h_scene = self.scene().parent().height()
            h = self.pixmap().height()
    
            t = painter.transform()
            s = (self.scale_percent*h_scene)/h
            self.setTransformOriginPoint(self.pixmap().width()/2, 0)
            painter.save()
    
            painter.setTransform(QtGui.QTransform(s, t.m12(), t.m13(),
                                                  t.m21(), s, t.m23(),
                                                  t.m31(), t.m32(), t.m33()))
            painter.translate(-self.pixmap().width()/2, 0)
    
            super().paint(painter, option, widget)
            if self._pen:
                painter.setPen(self._pen)
            painter.drawRect(self.pixmap().rect().translated(-self.pixmap().width()/2, 0))
    
            painter.restore()
    
        def boundingRect(self):
            h_scene = self.scene().parent().height()
            h = self.pixmap().height()
    
            s = (self.scale_percent*h_scene)/h
            r = self.pixmap().rect()
            r.setX((r.x() - self.pixmap().width()/2)*s)
            r.setY(r.y()*s)
            r.setWidth(r.width()*s)
            r.setHeight(r.height()*s)
    
            return r
    

    Con estos cambios, los elementos detectan correctamente los clics en sus posiciones escaladas y centradas.

Comments are closed.