Drawing QGraphicsObject at Mouse Position
-
Dear Experts, I'am struggling with mouse position mapping to a QGraphicsScene and any help is highly appreciated.
I've a custom QGraphicsScene class with a mouseMoveEvent emiting my mouse position like so:
class MyScene(QGraphicsScene): """ This is a custom QGraphicsScene implementation. """ hoverOnSceneSignal = QtCore.pyqtSignal(QPointF) .... def mouseMoveEvent(self, event): self.hoverOnSceneSignal.emit(event.scenePos()) super(MyScene, self).mouseMoveEvent(event)
Then I have a custom Widget drawing and image on a custom QGraphicsView with MyScene attached. This widget listens to the signal hoverOnSceneSignal:
class Viewer(QWidget): def __init__(self, parent=None): super(Viewer, self).__init__(parent=parent) self.myscene = MyScene(self) self.myview = MyView(self) self.myview.setScene(self.myscene) self._mousebrush = MouseBrushItem() def enterEvent(self, event): self.myscene.addItem(self._mousebrush) return super(Viewer, self).enterEvent(event) @QtCore.pyqtSlot(QPointF) def onHoverTriggered(self, pos): self._mousebrush.setPosition(pos)
_mousebrush is a custom QGraphicsObject added on MyScene painting an ellipse. The goal is to draw an ellipse at my mouse position, which should result in a photoshop like brush.
class MouseBrushItem(QGraphicsObject): def __init__(self): super(MouseBrushItem, self).__init__() self._size = 1 self._x = 0 self._y = 0 self._color = None self._pen = None self._brush = None self.setColor(QColor(255, 255, 255, 255)) def paint(self, painter, option, widget): rect = self.boundingRect() painter.setPen(self._pen) painter.setBrush(self._brush) painter.drawEllipse(rect) def boundingRect(self): return QRectF(self._x, self._y, self._size, self._size) def setColor(self, color): self._color = color self._pen = QPen(self._color, 1) self._brush = QBrush(QColor(self._color.red(), self._color.green(), self._color.blue(), 40)) def setSize(self, size): self._size = size def setPosition(self, pos): self._x = pos.x() self._y = pos.y() self.setPos(pos)
Unfortunately I'am not able to draw the circle sticked to my mouse. Everything works so far but the ellipse is running away from my mouse. I tried to play with mapFromWorld, mapToWorld, mapFromScene, mapToScene with no success. Seem I misunderstand anything important. Would be really thankful for comments helping me to draw a circle at my mouse if it moves on my QGraphicsScene.
Many Thanks and best regards
-
@Denni-0 Many Thanks for your good advices, I will take the time reading more about super. To be honest, I saw it in examples and consequently copied it expecting that it is the modern version of QWidget.init(self, parent=parent). I will also try to extract my problem to make the code small enough to post . Thought what I posted might be enough to see where my errors are.
-
@Denni-0 Here is a minimal code example, the question is how do I correctly draw the circle at the mouse position and get the coodinates on my pixmap for drawing? Can anyone help me with this issue?
import sys from PyQt5.QtCore import Qt, QRectF, QPointF from PyQt5.QtGui import QPixmap, QTransform, QBrush, QColor, QPen from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QSizePolicy, QSpacerItem, QGraphicsObject class MouseBrushObject(QGraphicsObject): def __init__(self): QGraphicsObject.__init__(self) self._size = 10 self._x = 0 self._y = 0 self._pen = None self._brush = None self._color = None self.setColor(QColor(255, 0, 0, 255)) def paint(self, painter, option, widget): rect = self.boundingRect() painter.setPen(self._pen) painter.setBrush(self._brush) painter.drawEllipse(rect) def boundingRect(self): return QRectF(self._x, self._y, self._size, self._size) def setColor(self, color): self._color = color self._pen = QPen(self._color, 1) self._brush = QBrush(QColor(self._color.red(), self._color.green(), self._color.blue(), 40)) def setSize(self, size): self._size = size def setPosition(self, pos): print(f"brush pos: {pos.x()}, {pos.y()}") self._x = pos.x()-self._size/2 self._y = pos.y()-self._size/2 self.setPos(QPointF(self._x, self._y)) class View(QGraphicsView): def __init__(self, parent=None): QGraphicsView.__init__(self, parent=parent) self.setMouseTracking(True) self.scene = QGraphicsScene(self) self.setScene(self.scene) pixmap = QPixmap(800, 440) self.scene.addItem(QGraphicsPixmapItem(pixmap)) self.setTransform(QTransform().scale(1, 1).rotate(0)) self.scene.setBackgroundBrush(QBrush(Qt.lightGray)) self._brushItem = MouseBrushObject() def mouseMoveEvent(self, event): pos = event.pos() #pos = self.mapToScene(pos) #pos = self.mapFromScene(pos) #pos = self.mapToGlobal(pos) #pos = self.mapFromGlobal(self.mapToGlobal(pos)) #pos = self.mapToGlobal(self.mapFromGlobal(pos)) #pos = self.mapToGlobal(self.mapFromScene(pos)) self._brushItem.setPosition(pos) def enterEvent(self, event): self.scene.addItem(self._brushItem) return super(View, self).enterEvent(event) def leaveEvent(self, event): self.scene.removeItem(self._brushItem) return super(View, self).leaveEvent(event) class Viewer(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent=parent) layout = QVBoxLayout() self.view = View(self) self.setLayout(layout) layout.addWidget(self.view) layout.addStretch(1) class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.viewer = Viewer(self) self.viewer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) layout = QVBoxLayout() layout.addWidget(self.viewer) centralwidget = QWidget(self) centralwidget.setLayout(layout) self.setCentralWidget(centralwidget) if __name__ == '__main__': app = QApplication(sys.argv) main = MainWindow() main.show() sys.exit(app.exec_())