PYQT : REPRÉSENTER UN POINT DANS UNE QGRAPHICSVIEW

Imaginons que l’on souhaite représenter un point dans une QGraphicsView. Il sera représenté par un cercle, dont on souhaite que le diamètre apparent ne change pas lorsqu’on zoome ou dézoome.

Commençons par ajouter une QGraphicsEllipseItem à la scène :

graphicsScene = QGraphicsScene()
graphicsView.setScene(graphicsScene) # La variable "graphicsView" contient une QGraphicsView

# Nous ajoutons un rectangle dont le coin haut gauche est à (0, 0), faisant 10 de large et 5 de haut :
graphicsScene.addRect(QRectF(0, 0, 10, 5))

# Nous ajoutons un cerle de diamètre 8 centré autour de (0, 0)
point = graphicsScene.addEllipse(QRectF(-4, -4, 8, 8), QPen(), QBrush(QtCore.Qt.red, QtCore.Qt.SolidPattern))

# Nous ajoutons la dimention de la scène pour englober tous les éléments qu'elle contient :
graphicsScene.setSceneRect(graphicsScene.itemsBoundingRect())
# On zoome de manière à voir l'ensemble de la scène, et pas plus :
graphicsView.fitInView(graphicsScene.sceneRect(), QtCore.Qt.KeepAspectRatio)
# On peut éventuellement dézommer un peu pour avoir une marge autour des éléments
graphicsView.scale(0.875, 0.875)

Nous obtenons le résultat suivant :

Le « point » (cercle) est au bon endroit, mais on souhaite maintenant qu’il ait toujours un diamètre apparent de 8×8 pixels, quel que soit le niveau de zoom.

Pour cela il faut ajouter :

    point.setFlag(QGraphicsItem.ItemIgnoresTransformations)

Après le addEllipse()

Ce qui nous donne :

Le point a maintenant la dimension apparente que l’on souhaite, mais un autre problème se pose : il y a une énorme marge autour de lui.

Cela se produit car le flag ItemIgnoresTransformations ne s’applique qu’à l’apparence de l’élément, et pas à son rectangle délimitant (« bounding rectangle »).

On peut remédier à cela en créant notre propre classe, qui va hériter de QGraphicsEllipseItem, et redéfinir la méthode boundingRect() :

class ZeroSizedGraphicsEllipseItem(QGraphicsEllipseItem):
    def boundingRect(self):
        """Bounding rect infinitésimal (infiniment petit)"""
        # On retourne un "bounding rect" de taille 0 x 0 :
        return QRectF(self.x(), self.y(), 0, 0)
Ainsi, le code devient :
graphicsScene = QtGui.QGraphicsScene()
graphicsView.setScene(graphicsScene) # La variable "graphicsView" contient une QGraphicsView

# On ajoute un rectangle dont le coin haut gauche est à (0, 0), faisant 10 de large et 5 de haut :
graphicsScene.addRect(QRectF(0, 0, 10, 5))

# On ajoute un cerle de diamètre 8 centré autour de (0, 0) :
point = ZeroSizedGraphicsEllipseItem(QRectF(-4, -4, 8, 8))
point.setBrush(QBrush(QtCore.Qt.red, QtCore.Qt.SolidPattern))
graphicsScene.addItem(point)
# Ne pas le redimensionner quand on zoome / dézoome :
point.setFlag(QGraphicsItem.ItemIgnoresTransformations)

# On ajuste la dimention de la scène pour englober tous les éléments qu'elle contient :
graphicsScene.setSceneRect(graphicsScene.itemsBoundingRect())
# On zoome de manière à voir l'ensemble de la scène, et pas plus :
graphicsView.fitInView(graphicsScene.sceneRect(), QtCore.Qt.KeepAspectRatio)
# On peut éventuellement dézommer un peu pour avoir une marge autour des éléments
graphicsView.scale(0.875, 0.875)
On obtient donc l’image suivante :
GQraphicsview
PYQT4
Python
QGraphicsScene
QGraphicsSellipseitem
QT
Publié par Evolutis

Compte de publication d'Evolutis