Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Drawing a custom arbitrary shape (ellipse/polygon)



  • Hello,

    I am trying to make a QGraphicsItem draw a polygon based on a custom class:

    class Shape:
    
        shapes = {
            'square': [(-4, -4), (4, -4), (4, 4), (-4, 4)],
            'triangle': [(0, -4), (4, 4), (-4, 4)],
            'star': [(-1, -1), (0, -6), (1, -1), (5, 4), (0, 1), (-5, 4), (-1, -1)],
            'x': [(0, -2), (3, -5), (5, -3), (2, 0), (5, 3),
                (3, 5), (0, 2), (-3, 5), (-5, 3), (-2, 0), (-5, -3), (-3, -5)]
        }
    
        def __init__(self, name):
            self.name = name
            self._scale = 1
            self._shape = self.build_shape(self.name)
    
        def build_shape(self, shape_name):
                # Build QPolygon dictionary from Shapes coordinates
                shape = QPolygon([QPoint(*point) * self.scale
                        for point in Shape.shapes[shape_name]])
                return shape
    
        @property
        def name(self):
            return self._name
        
        @name.setter
        def name(self, value):
            if value not in self.shapes.keys():
                e = f'Invalid Shape name: "{value}" '
                e += f'(valid Shapes are: {list(self.shapes.keys())})'
                raise ValueError(e)
            self._name = value
    
        # No setter as this is read-only
        @property
        def shape(self):
            return self._shape
    
        @property
        def scale(self):
                return self._scale
    
        @scale.setter
        def scale(self, value: float):
            if not 0.5 <= value <= 3:
                e = f'Invalid Shape scale: {value} '
                e += f'(valid Shape scale range is 0.5 to 3)'
                raise ValueError(e)
            else:
                self._scale = value
                # Rebuild the shape with the new scale factor
                self._shape = self.build_shape(self.name)
    

    I can then do a drawPolygon(shape) in my QGraphicsItem-derived class.

    Now, I would like to use a default circle if no shape name is provided, but I do not want to do it inside the QGraphicsItem class, like this:

            if shape.name == 'circle':
                painter.drawEllipse(-2, -2, 4, 4)
            else:
                painter.drawPolygon(shape.shape)
    

    Rather, I would like this behavior to be set up in the Shape class, which would return either an ellipse or a polygon, to be drawn later inside QGraphicsItem. If the default shape needs to be changed later, I'd like to be able to do it from within the Shape class, and not anywhere else.

    I can't find a way to return something like a QEllipse (which doesn't exist). Is there a QPainter method which can accept either an ellipse or a polygon, and draw either?

    Thanks.


  • Lifetime Qt Champion

    Hi,

    The simplest would be to pass the painter to your helper class and let it do the correct call.

    Add a draw method for that.



  • @SGaist Thanks a lot. I thought about that, but then I realised I would be much better off doing all of this with Unicode symbols instead of drawing vector shapes, which has simpified everything greatly :)


Log in to reply