2 votes

PyQt: QGraphicsItem ajouté à une mauvaise position

J'ai une sous-classe de QGraphicsItem et je veux ajouter des instances de celle-ci à la scène sur un clic avec 'Ctrl + clic gauche'. Le problème est que l'élément est ajouté à une position avec des coordonnées deux fois plus grandes qu'elles ne devraient l'être. En même temps, l'ajout d'ellipses avec scene.addEllipse(...) fonctionne bien.

#!/usr/bin/env python

import sys
from PyQt4.QtCore import (QPointF, QRectF, Qt, )
from PyQt4.QtGui import (QApplication, QMainWindow, QGraphicsItem, 
                         QGraphicsScene, QGraphicsView, QPen, QStyle)

MapSize = (512, 512)

class DraggableMark(QGraphicsItem):
    def __init__(self, position, scene):
        super(DraggableMark, self).__init__(None, scene)
        self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable)
        self.rect = QRectF(position.x(), position.y(), 15, 15)
        self.setPos(position)
        scene.clearSelection()

    def boundingRect(self):
        return self.rect

    def paint(self, painter, option, widget):
        pen = QPen(Qt.SolidLine)
        pen.setColor(Qt.black)
        pen.setWidth(1)
        if option.state & QStyle.State_Selected:
            pen.setColor(Qt.blue)
        painter.setPen(pen)
        painter.drawEllipse(self.rect)

class GraphicsScene(QGraphicsScene):
    def __init__(self, parent=None):
        super(GraphicsScene, self).__init__(parent)
        self.setSceneRect(0, 0, *MapSize)

    def mousePressEvent(self, event):
        super(GraphicsScene, self).mousePressEvent(event)
        if event.button() != Qt.LeftButton:
            return

        modifiers = QApplication.keyboardModifiers()
        pos = event.scenePos()
        if modifiers == Qt.ControlModifier:
            print("Ctrl + Clic: (%d, %d)" % (pos.x(), pos.y()))
            DraggableMark(pos, self)
            self.addEllipse(QRectF(pos.x(), pos.y(), 10, 10))
        else:
            print("Clic: (%d, %d)" % (pos.x(), pos.y()))

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.scene = GraphicsScene(self)
        self.scene.addRect(QRectF(0, 0, *MapSize), Qt.red)
        self.view = QGraphicsView()
        self.view.setScene(self.scene)
        self.view.resize(self.scene.width(), self.scene.height())
        self.setCentralWidget(self.view)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    rect = QApplication.desktop().availableGeometry()
    window.resize(int(rect.width()), int(rect.height()))
    window.show()
    app.exec_()

8voto

rbaleksandar Points 156

Je vois que vous avez répondu à votre propre question. Cependant, j'aimerais expliquer pourquoi cela fonctionne.

Chaque QGraphicsItem a son propre système de coordonnées local. Donc lorsque vous faites

self.rect = QRectF(position.x(), position.y(), 15, 15)

vous partez essentiellement du point (0, 0) du système de coordonnées local de l'élément et vous vous rendez aux x et y donnés provenant de position. Cela signifie essentiellement que votre rectangle sera dessiné à position.x() + position.x() et position.y() + position.y() avec le premier position.x()/position.y() étant la position du QGraphicsItem dans votre scène et le deuxième position.x()/position.y() étant la position dans le système de coordonnées local de votre élément.

Si vous voulez partir de l'origine du QGraphicsItem, vous devez utiliser

 self.rect = QRectF(0, 0, 15, 15)

Cela assure que vous partez de l'origine du système de coordonnées local.

Ce problème est particulièrement délicat car par défaut, les objets sont ajoutés au point (0, 0) d'une scène. Ainsi, position.x() + position.x() et position.y() + position.y() dans ce cas ne montreront pas le problème en question puisque 0+0 est toujours égal à 0. C'est au moment où vous changez la position par défaut à autre chose que le problème surviendra.

Voici une figure en 3D qui visualise ce que je viens de décrire ci-dessus (je n'ai pas pu trouver d'exemple en 2D mais le principe est le même :P) :

entrer la description de l'image ici

Le monde ici est la scène tandis que l'objet est le QGraphicsItem résidant dans cette scène.

1voto

A_buddy Points 35

Changer

self.rect = QRectF(position.x(), position.y(), 15, 15)

à

self.rect = QRectF(0, 0, 15, 15)

a résolu le problème

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X