class MarkerFactory(QObject): """ Parameters ------------ shape: Shape See config.Shape color: str, QColor Color of the marker. Marker must be filled and outlined with the same color. size: int Width and height of the output QGraphicsItem filled: bool Whether to fill the item. """ _shape_to_class = EnumDict([(Shape.CIRCLE, EllipseMarker), (Shape.DIAMOND, DiamondMarker)]) def __init__(self, shape=Shape.CIRCLE, color=Qt.red, size=3, filled=True): super().__init__() self._brush = QBrush() self._pen = QPen() self.set_marker_shape(shape) self.set_marker_size(size) self.set_marker_color(color) self.set_marker_fill(filled) def get_marker_color(self) -> QColor: return self._pen.color() def set_marker_color(self, color: Union[QColor, int]): # XXX: what's the difference between settning alpha to 0 and # passing Qt.NoBrush to the constructor? # filled = deepcopy(self._brush.style()) self._pen.setColor(color) self._brush.setColor(color) # self._brush.setStyle(filled) def get_marker_fill(self) -> bool: return bool(self._brush.style()) def set_marker_fill(self, f: bool): if f: style = Qt.SolidPattern else: style = Qt.NoBrush self._brush.setStyle(style) def get_marker_shape(self) -> Shape: return self._shape def set_marker_shape(self, shape: Shape): self._shape = shape def get_marker_size(self): return self._size def set_marker_size(self, size: int): self._size = size def __call__(self, x: float, y: float, **kwargs: Any) -> Marker: """ Create a Marker with the properties specified by this Factory. Parameters ------------ x : float y : float X, Y coordinates of the marker. key : int Index that this marker will have in the parent VGraphicsGroup. """ marker = TunableMarker(self._shape, self._size, key=None, **kwargs) marker.set_marker_color(self.get_marker_color()) marker.set_marker_fill(self.get_marker_fill()) # marker = self._marker_class(self._size, **kwargs) # marker.setBrush(self._brush) # marker.setPen(self._pen) marker.setPos(x, y) return marker
class TunableMarker(QGraphicsItem): def __init__(self, shape: Shape, size: int, key: Optional[int] = None, **kwargs): super().__init__() self._shape = shape self._size = size self.key = key self.info = kwargs self._pen = QPen() self._pen.setWidthF(0.25) self._brush = QBrush() def _make_rect(self, length): # make a rectangle of width and height equal to 'length' and centered # about (0, 0) return QRectF(-length / 2, -length / 2, length, length) def boundingRect(self): return self._make_rect(self._size + 4) def _paint_ellipse(self, painter): rect = self._make_rect(self._size) painter.drawEllipse(rect) def _paint_diamond(self, painter): size = self._size X = [0, size / 2, 0, -size / 2, 0] Y = [size / 2, 0, -size / 2, 0, size / 2] points = [QPointF(x, y) for x, y in zip(X, Y)] polygon = QPolygonF(points) painter.drawPolygon(polygon, len(points)) def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem, widget: QWidget): painter.setPen(self._pen) painter.setBrush(self._brush) shape_to_paint_method = { Shape.CIRCLE: self._paint_ellipse, Shape.DIAMOND: self._paint_diamond } drawing_method = shape_to_paint_method[self._shape] drawing_method(painter) def get_marker_color(self): """ Marker color. """ return self._pen.color() def set_marker_color(self, color: Union[QColor, int]): color = QColor(color) self._pen.setColor(color) self._brush.setColor(color) self.update() def get_marker_fill(self) -> bool: """ Whether this marker is filled in or merely an outline. """ return bool(self._brush.style()) def set_marker_fill(self, f: bool): if f: f = Qt.SolidPattern else: f = Qt.NoBrush self._brush.setStyle(f) self.update() def get_marker_shape(self): return self._shape def set_marker_shape(self, shape: Shape): self._shape = shape self.update() def get_marker_size(self): return self._size def set_marker_size(self, sz: int): self._size = sz self.update()