Пример #1
0
    def paintEvent(self, e):
        if self.points is None:
            return
        painter = QPainter(self)
        pen = QPen()  # creates a default pen

        pen.setWidth(2)
        pen.setCapStyle(Qt.RoundCap)
        pen.setJoinStyle(Qt.RoundJoin)
        painter.setPen(pen)
        painter.setRenderHint(QPainter.Antialiasing)

        # to avoid zero division
        m = max(max(self.points), 10)
        for i, v in enumerate(self.points):
            pen.setBrush(self.colors[min(v * len(self.colors) // m,
                                         len(self.colors) - 1)])
            painter.setPen(pen)
            painter.drawLine(
                40 + 5 * i,
                self.height() // 2 - min(v, self.height()) // 2,
                40 + 5 * i,
                self.height() // 2 + min(v, self.height()) // 2,
            )

        painter.end()
Пример #2
0
def qwtDrawXCrossSymbols(painter, points, numPoints, symbol):
    size = symbol.size()
    pen = QPen(symbol.pen())
    if pen.width() > 1:
        pen.setCapStyle(Qt.FlatCap)
    painter.setPen(pen)
    sw = size.width()
    sh = size.height()
    sw2 = 0.5 * size.width()
    sh2 = 0.5 * size.height()
    for pos in points:
        x1 = pos.x() - sw2
        x2 = x1 + sw
        y1 = pos.y() - sh2
        y2 = y1 + sh
        painter.drawLine(x1, y1, x2, y2)
        painter.drawLine(x2, y1, x1, y2)
Пример #3
0
def qwtDrawLineSymbols(painter, orientations, points, numPoints, symbol):
    size = symbol.size()
    pen = QPen(symbol.pen())
    if pen.width() > 1:
        pen.setCapStyle(Qt.FlatCap)
    painter.setPen(pen)
    painter.setRenderHint(QPainter.Antialiasing, False)
    sw = size.width()
    sh = size.height()
    sw2 = 0.5 * size.width()
    sh2 = 0.5 * size.height()
    for pos in points:
        if orientations & Qt.Horizontal:
            x = round(pos.x()) - sw2
            y = round(pos.y())
            painter.drawLine(x, y, x + sw, y)
        if orientations & Qt.Vertical:
            x = round(pos.x())
            y = round(pos.y()) - sh2
            painter.drawLine(x, y, x, y + sh)
Пример #4
0
def qwtDrawStar2Symbols(painter, points, numPoints, symbol):
    pen = QPen(symbol.pen())
    if pen.width() > 1:
        pen.setCapStyle(Qt.FlatCap)
    pen.setJoinStyle(Qt.MiterJoin)
    painter.setPen(pen)
    painter.setBrush(symbol.brush())
    cos30 = np.cos(30 * np.pi / 180.0)
    dy = 0.25 * symbol.size().height()
    dx = 0.5 * symbol.size().width() * cos30 / 3.0
    for pos in points:
        x = pos.x()
        y = pos.y()
        x1 = x - 3 * dx
        y1 = y - 2 * dy
        x2 = x1 + 1 * dx
        x3 = x1 + 2 * dx
        x4 = x1 + 3 * dx
        x5 = x1 + 4 * dx
        x6 = x1 + 5 * dx
        x7 = x1 + 6 * dx
        y2 = y1 + 1 * dy
        y3 = y1 + 2 * dy
        y4 = y1 + 3 * dy
        y5 = y1 + 4 * dy
        star = [
            QPointF(x4, y1),
            QPointF(x5, y2),
            QPointF(x7, y2),
            QPointF(x6, y3),
            QPointF(x7, y4),
            QPointF(x5, y4),
            QPointF(x4, y5),
            QPointF(x3, y4),
            QPointF(x1, y4),
            QPointF(x2, y3),
            QPointF(x1, y2),
            QPointF(x3, y2),
        ]
        painter.drawPolygon(QPolygonF(star))
Пример #5
0
 def drawRoundedFrame(self, painter, rect, xRadius, yRadius, palette,
                      lineWidth, frameStyle):
     """
     Draw a rectangular frame with rounded borders
     
     :param QPainter painter: Painter
     :param QRectF rect: Frame rectangle
     :param float xRadius: x-radius of the ellipses defining the corners
     :param float yRadius: y-radius of the ellipses defining the corners
     :param QPalette palette: `QPalette.WindowText` is used for plain borders, `QPalette.Dark` and `QPalette.Light` for raised or sunken borders
     :param int lineWidth: Line width
     :param int frameStyle: bitwise OR´ed value of `QFrame.Shape` and `QFrame.Shadow`
     """
     painter.save()
     painter.setRenderHint(QPainter.Antialiasing, True)
     painter.setBrush(Qt.NoBrush)
     lw2 = lineWidth * 0.5
     r = rect.adjusted(lw2, lw2, -lw2, -lw2)
     path = QPainterPath()
     path.addRoundedRect(r, xRadius, yRadius)
     Plain, Sunken, Raised = list(range(3))
     style = Plain
     if (frameStyle & QFrame.Sunken) == QFrame.Sunken:
         style = Sunken
     if (frameStyle & QFrame.Raised) == QFrame.Raised:
         style = Raised
     if style != Plain and path.elementCount() == 17:
         pathList = [QPainterPath() for _i in range(8)]
         for i in range(4):
             j = i * 4 + 1
             pathList[2 * i].moveTo(
                 path.elementAt(j - 1).x,
                 path.elementAt(j - 1).y)
             pathList[2 * i].cubicTo(
                 path.elementAt(j + 0).x,
                 path.elementAt(j + 0).y,
                 path.elementAt(j + 1).x,
                 path.elementAt(j + 1).y,
                 path.elementAt(j + 2).x,
                 path.elementAt(j + 2).y,
             )
             pathList[2 * i + 1].moveTo(
                 path.elementAt(j + 2).x,
                 path.elementAt(j + 2).y)
             pathList[2 * i + 1].lineTo(
                 path.elementAt(j + 3).x,
                 path.elementAt(j + 3).y)
         c1 = QColor(palette.color(QPalette.Dark))
         c2 = QColor(palette.color(QPalette.Light))
         if style == Raised:
             c1, c2 = c2, c1
         for i in range(5):
             r = pathList[2 * i].controlPointRect()
             arcPen = QPen()
             arcPen.setCapStyle(Qt.FlatCap)
             arcPen.setWidth(lineWidth)
             linePen = QPen()
             linePen.setCapStyle(Qt.FlatCap)
             linePen.setWidth(lineWidth)
             if i == 0:
                 arcPen.setColor(c1)
                 linePen.setColor(c1)
             elif i == 1:
                 gradient = QLinearGradient()
                 gradient.setStart(r.topLeft())
                 gradient.setFinalStop(r.bottomRight())
                 gradient.setColorAt(0.0, c1)
                 gradient.setColorAt(1.0, c2)
                 arcPen.setBrush(gradient)
                 linePen.setColor(c2)
             elif i == 2:
                 arcPen.setColor(c2)
                 linePen.setColor(c2)
             elif i == 3:
                 gradient = QLinearGradient()
                 gradient.setStart(r.bottomRight())
                 gradient.setFinalStop(r.topLeft())
                 gradient.setColorAt(0.0, c2)
                 gradient.setColorAt(1.0, c1)
                 arcPen.setBrush(gradient)
                 linePen.setColor(c1)
             painter.setPen(arcPen)
             painter.drawPath(pathList[2 * i])
             painter.setPen(linePen)
             painter.drawPath(pathList[2 * i + 1])
     else:
         pen = QPen(palette.color(QPalette.WindowText), lineWidth)
         painter.setPen(pen)
         painter.drawPath(path)
     painter.restore()
Пример #6
0
class PyDMDrawing(QWidget, PyDMWidget):
    """
    Base class to be used for all PyDM Drawing Widgets.
    This class inherits from QWidget and PyDMWidget.

    Parameters
    ----------
    parent : QWidget
        The parent widget for the Label
    init_channel : str, optional
        The channel to be used by the widget.
    """
    def __init__(self, parent=None, init_channel=None):
        self._rotation = 0.0
        self._brush = QBrush(Qt.SolidPattern)
        self._original_brush = None
        self._painter = QPainter()
        self._pen = QPen(Qt.NoPen)
        self._pen_style = Qt.NoPen
        self._pen_cap_style = Qt.SquareCap
        self._pen_join_style = Qt.MiterJoin
        self._pen_width = 0
        self._pen_color = QColor(0, 0, 0)
        self._pen.setCapStyle(self._pen_cap_style)
        self._pen.setJoinStyle(self._pen_join_style)
        self._original_pen_style = self._pen_style
        self._original_pen_color = self._pen_color
        QWidget.__init__(self, parent)
        PyDMWidget.__init__(self, init_channel=init_channel)
        self.alarmSensitiveBorder = False

    def sizeHint(self):
        return QSize(100, 100)

    def paintEvent(self, _):
        """
        Paint events are sent to widgets that need to update themselves,
        for instance when part of a widget is exposed because a covering
        widget was moved.

        At PyDMDrawing this method handles the alarm painting with parameters
        from the stylesheet, configures the brush, pen and calls ```draw_item```
        so the specifics can be performed for each of the drawing classes.

        Parameters
        ----------
        event : QPaintEvent
        """
        painter = QPainter(self)
        opt = QStyleOption()
        opt.initFrom(self)
        self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self)
        painter.setRenderHint(QPainter.Antialiasing)

        painter.setBrush(self._brush)
        painter.setPen(self._pen)

        self.draw_item(painter)

    def draw_item(self, painter):
        """
        The classes inheriting from PyDMDrawing must overwrite this method.
        This method translate the painter to the center point given by
        ```get_center``` and rotate the canvas by the given amount of
        degrees.
        """
        xc, yc = self.get_center()
        painter.translate(xc, yc)
        painter.rotate(-self._rotation)

    def get_center(self):
        """
        Simple calculation of the canvas' center point.

        Returns
        -------
        x, y : float
            Tuple with X and Y coordinates of the center.
        """
        return self.width() * 0.5, self.height() * 0.5

    def get_bounds(self, maxsize=False, force_no_pen=False):
        """
        Returns a tuple containing the useful area for the drawing.

        Parameters
        ----------
        maxsize : bool, default is False
            If True, width and height information are based on the
            maximum inner rectangle dimensions given by ```get_inner_max```,
            otherwise width and height will receive the widget size.

        force_no_pen : bool, default is False
            If True the pen width will not be considered when calculating
            the bounds.

        Returns
        -------
        x, y, w, h : tuple
            Tuple with X and Y coordinates followed by the maximum width
            and height.
        """
        w, h = self.width(), self.height()

        if maxsize:
            w, h = self.get_inner_max()

        xc, yc = w * 0.5, h * 0.5

        if self.has_border() and not force_no_pen:
            w = max(0, w - 2 * self._pen_width)
            h = max(0, h - 2 * self._pen_width)
            x = max(0, self._pen_width)
            y = max(0, self._pen_width)
        else:
            x = 0
            y = 0
        return x - xc, y - yc, w, h

    def has_border(self):
        """
        Check whether or not the drawing have a border based on the
        Pen Style and Pen width.

        Returns
        -------
        bool
            True if the drawing has a border, False otherwise.
        """
        if self._pen.style() != Qt.NoPen and self._pen_width > 0:
            return True
        else:
            return False

    def is_square(self):
        """
        Check if the widget has the same width and height values.

        Returns
        -------
        bool
            True in case the widget has a square shape, False otherwise.
        """
        return self.height() == self.width()

    def get_inner_max(self):
        """
        Calculates the largest inner rectangle in a rotated rectangle.
        This implementation was based on https://stackoverflow.com/a/18402507

        Returns
        -------
        w, h : tuple
            The width and height of the largest rectangle.
        """
        # Based on https://stackoverflow.com/a/18402507
        w0 = 0
        h0 = 0
        angle = math.radians(self._rotation)
        origWidth = self.width()
        origHeight = self.height()

        if origWidth == 0:
            logger.error(
                "Invalid width. The value must be greater than {0}".format(
                    origWidth))
            return

        if origHeight == 0:
            logger.error(
                "Invalid height. The value must be greater than {0}".format(
                    origHeight))
            return

        if (origWidth <= origHeight):
            w0 = origWidth
            h0 = origHeight
        else:
            w0 = origHeight
            h0 = origWidth
        # Angle normalization in range [-PI..PI)
        ang = angle - math.floor(
            (angle + math.pi) / (2 * math.pi)) * 2 * math.pi
        ang = math.fabs(ang)
        if ang > math.pi / 2:
            ang = math.pi - ang
        c = w0 / (h0 * math.sin(ang) + w0 * math.cos(ang))
        w = 0
        h = 0
        if (origWidth <= origHeight):
            w = w0 * c
            h = h0 * c
        else:
            w = h0 * c
            h = w0 * c
        return w, h

    @Property(QBrush)
    def brush(self):
        """
        PyQT Property for the brush object to be used when coloring the
        drawing

        Returns
        -------
        QBrush
        """
        return self._brush

    @brush.setter
    def brush(self, new_brush):
        """
        PyQT Property for the brush object to be used when coloring the
        drawing

        Parameters
        ----------
        new_brush : QBrush
        """
        if new_brush != self._brush:
            if self._alarm_state == PyDMWidget.ALARM_NONE:
                self._original_brush = new_brush
            self._brush = new_brush
            self.update()

    @Property(Qt.PenStyle)
    def penStyle(self):
        """
        PyQT Property for the pen style to be used when drawing the border

        Returns
        -------
        int
            Index at Qt.PenStyle enum
        """
        return self._pen_style

    @penStyle.setter
    def penStyle(self, new_style):
        """
        PyQT Property for the pen style to be used when drawing the border

        Parameters
        ----------
        new_style : int
            Index at Qt.PenStyle enum
        """
        if self._alarm_state == PyDMWidget.ALARM_NONE:
            self._original_pen_style = new_style
        if new_style != self._pen_style:
            self._pen_style = new_style
            self._pen.setStyle(new_style)
            self.update()

    @Property(Qt.PenCapStyle)
    def penCapStyle(self):
        """
        PyQT Property for the pen cap to be used when drawing the border

        Returns
        -------
        int
            Index at Qt.PenCapStyle enum
        """
        return self._pen_cap_style

    @penCapStyle.setter
    def penCapStyle(self, new_style):
        """
        PyQT Property for the pen cap style to be used when drawing the border

        Parameters
        ----------
        new_style : int
            Index at Qt.PenStyle enum
        """
        if new_style != self._pen_cap_style:
            self._pen_cap_style = new_style
            self._pen.setCapStyle(new_style)
            self.update()

    @Property(Qt.PenJoinStyle)
    def penJoinStyle(self):
        """
        PyQT Property for the pen join style to be used when drawing the border

        Returns
        -------
        int
            Index at Qt.PenJoinStyle enum
        """
        return self._pen_join_style

    @penJoinStyle.setter
    def penJoinStyle(self, new_style):
        """
        PyQT Property for the pen join style to be used when drawing the border

        Parameters
        ----------
        new_style : int
            Index at Qt.PenStyle enum
        """
        if new_style != self._pen_join_style:
            self._pen_join_style = new_style
            self._pen.setJoinStyle(new_style)
            self.update()

    @Property(QColor)
    def penColor(self):
        """
        PyQT Property for the pen color to be used when drawing the border

        Returns
        -------
        QColor
        """
        return self._pen_color

    @penColor.setter
    def penColor(self, new_color):
        """
        PyQT Property for the pen color to be used when drawing the border

        Parameters
        ----------
        new_color : QColor
        """
        if self._alarm_state == PyDMWidget.ALARM_NONE:
            self._original_pen_color = new_color

        if new_color != self._pen_color:
            self._pen_color = new_color
            self._pen.setColor(new_color)
            self.update()

    @Property(float)
    def penWidth(self):
        """
        PyQT Property for the pen width to be used when drawing the border

        Returns
        -------
        float
        """
        return self._pen_width

    @penWidth.setter
    def penWidth(self, new_width):
        """
        PyQT Property for the pen width to be used when drawing the border

        Parameters
        ----------
        new_width : float
        """
        if new_width < 0:
            return
        if new_width != self._pen_width:
            self._pen_width = new_width
            self._pen.setWidth(self._pen_width)
            self.update()

    @Property(float)
    def rotation(self):
        """
        PyQT Property for the counter-clockwise rotation in degrees
        to be applied to the drawing.

        Returns
        -------
        float
        """
        return self._rotation

    @rotation.setter
    def rotation(self, new_angle):
        """
        PyQT Property for the counter-clockwise rotation in degrees
        to be applied to the drawing.

        Parameters
        ----------
        new_angle : float
        """
        if new_angle != self._rotation:
            self._rotation = new_angle
            self.update()

    def alarm_severity_changed(self, new_alarm_severity):
        PyDMWidget.alarm_severity_changed(self, new_alarm_severity)
        if new_alarm_severity == PyDMWidget.ALARM_NONE:
            if self._original_brush is not None:
                self.brush = self._original_brush
            if self._original_pen_color is not None:
                self.penColor = self._original_pen_color
            if self._original_pen_style is not None:
                self.penStyle = self._original_pen_style
Пример #7
0
    def draw(self, painter, xMap, yMap, canvasRect):
        """
        Draw the grid

        The grid is drawn into the bounding rectangle such that
        grid lines begin and end at the rectangle's borders. The X and Y
        maps are used to map the scale divisions into the drawing region
        screen.

        :param QPainter painter: Painter
        :param qwt.scale_map.QwtScaleMap xMap: X axis map
        :param qwt.scale_map.QwtScaleMap yMap: Y axis
        :param QRectF canvasRect: Contents rectangle of the plot canvas
        """
        minorPen = QPen(self.__data.minorPen)
        minorPen.setCapStyle(Qt.FlatCap)
        painter.setPen(minorPen)
        if self.__data.xEnabled and self.__data.xMinEnabled:
            self.drawLines(
                painter,
                canvasRect,
                Qt.Vertical,
                xMap,
                self.__data.xScaleDiv.ticks(QwtScaleDiv.MinorTick),
            )
            self.drawLines(
                painter,
                canvasRect,
                Qt.Vertical,
                xMap,
                self.__data.xScaleDiv.ticks(QwtScaleDiv.MediumTick),
            )
        if self.__data.yEnabled and self.__data.yMinEnabled:
            self.drawLines(
                painter,
                canvasRect,
                Qt.Horizontal,
                yMap,
                self.__data.yScaleDiv.ticks(QwtScaleDiv.MinorTick),
            )
            self.drawLines(
                painter,
                canvasRect,
                Qt.Horizontal,
                yMap,
                self.__data.yScaleDiv.ticks(QwtScaleDiv.MediumTick),
            )
        majorPen = QPen(self.__data.majorPen)
        majorPen.setCapStyle(Qt.FlatCap)
        painter.setPen(majorPen)
        if self.__data.xEnabled:
            self.drawLines(
                painter,
                canvasRect,
                Qt.Vertical,
                xMap,
                self.__data.xScaleDiv.ticks(QwtScaleDiv.MajorTick),
            )
        if self.__data.yEnabled:
            self.drawLines(
                painter,
                canvasRect,
                Qt.Horizontal,
                yMap,
                self.__data.yScaleDiv.ticks(QwtScaleDiv.MajorTick),
            )