class RoundAnimation(QPropertyAnimation):

    def __init__(self, target, prop, parent=None):
        super(RoundAnimation, self).__init__(target, prop, parent)

    def updateCurrentTime(self, currentTime):
        self.path = QPainterPath()
        if self.path.isEmpty():
            end = self.endValue()
            start = self.startValue()
            self.path.addEllipse(QRectF(start, end))

        duration = self.duration()

        if duration == 0:
            progress = 1.0
        else:
            progress = (((currentTime - 1) % duration) + 1) / float(duration)

        easedProgress = self.easingCurve().valueForProgress(progress)

        if easedProgress > 1.0:
            easedProgress -= 1.0
        elif easedProgress < 0:
            easedProgress += 1.0

        pt = self.path.pointAtPercent(easedProgress)
        self.updateCurrentValue(pt)
class Animation(QPropertyAnimation):
    '''
    动画类
    '''
    def __init__(self, target, prop):
        '''
        target, prop这个两个参数分别对应:动画的产生对象和setter
        '''
        super(Animation, self).__init__(target, prop)

    def updateCurrentTime(self, currentTime):
        '''
        currentTime(此属性保存动画的当前时间和进度)总是在变化的。
        每次动画的currentTime更改时,都会调用updateCurrentTime()函数
        '''
        self.m_path = QPainterPath()
        if self.m_path.isEmpty():
            end = self.endValue()
            start = self.startValue()
            # endValue()、startValue()分别表示动画的结束值和起始值
            self.m_path.addEllipse(QRectF(start, end))
            # 在指定的boundingRectangle内创建一个椭圆,这里是QRectF(start, end),并将其作为封闭的子路径添加到painter路径中。

        dura = self.duration()
        progress = (((currentTime - 1) % dura) + 1) / float(dura)
        # duration()此属性保存动画的持续时间(以毫秒为单位)。 默认持续时间为250毫秒。progress则描绘了当前的完成比率。

        easedProgress = self.easingCurve().valueForProgress(progress)
        if easedProgress > 1.0:
            easedProgress -= 1.0
        elif easedProgress < 0:
            easedProgress += 1.0
        # 返回进度缓和曲线的有效进度。 进度必须介于0和1之间,而返回的有效进度可能超出这些范围。大于1就减1,小于0就加1。

        pt = self.m_path.pointAtPercent(easedProgress)
        # 返回当前路径的百分比easedProgress处的点。
        # 参数easedProgress必须介于0和1之间。当存在曲线时,百分比参数被映射到贝塞尔方程的t参数。

        self.updateCurrentValue(pt)
        # 每次动画的当前值更改时,都会调用updateCurrentValue()。pt参数是新的当前值。没有这个函数动画动不了。

        self.valueChanged.emit(pt)

    def startAnimation(self, startx, starty, endx, endy, duration):
        '''
        setStartValue()、setEndValue()分别表示设置动画的起止位置,setDuration()设置动画的运行时间。
        '''
        self.setStartValue(QPointF(startx, starty))
        self.setEndValue(QPointF(endx, endy))
        self.setDuration(duration)
        self.setLoopCount(-1)
        # 值为-1时,动画将永远循环直至停止

        self.start()
Exemple #3
0
class _MoveAnimation(QPropertyAnimation):
    '''move animation'''

    MOVE1 = 1
    MOVE2 = 2
    MOVE3 = 3

    def __init__(self, target, parent, easing=QEasingCurve.Custom):
        super(_MoveAnimation, self).__init__(target, b"pos")
        self.parent = parent
        self.easing = easing
        if easing != -1:
            self.setEasingCurve(easing)
        self.m_path = QPainterPath()

    def setMoveType(self, _type):
        self._type = _type

    def updateCurrentTime(self, currentTime):
        if self.m_path.isEmpty():
            # end = self.endValue()
            start = self.startValue()
            if self._type == self.MOVE1:
                end = QPoint(self.parent.width() / 4.0, 0)
            elif self._type == self.MOVE2:
                end = QPoint((self.parent.width() / 4.0) * 3.0, 0)
                if not start:
                    start = QPoint(self.parent.width() / 4.0, 0)
                    # 第二个移动没有设置开始坐标,这里以第一个移动结束为开始
            elif self._type == self.MOVE3:
                if not start:
                    start = QPoint((self.parent.width() / 4.0) * 3.0, 0)
                    # 第三个移动没有设置开始坐标,这里以第二个移动结束为开始
                end = QPoint(self.parent.width(), 0)
            self.m_path.moveTo(start)
            self.m_path.addEllipse(QRectF(start, end))

        dura = self.duration()
        if dura == 0:
            progress = 1.0
        else:
            progress = (((currentTime - 1) % dura) + 1) / float(dura)

        easedProgress = self.easingCurve().valueForProgress(progress)
        if easedProgress > 1.0:
            easedProgress -= 1.0
        elif easedProgress < 0:
            easedProgress += 1.0

        pt = self.m_path.pointAtPercent(easedProgress)
        self.updateCurrentValue(pt)
        self.valueChanged.emit(pt)
        super(_MoveAnimation, self).updateCurrentTime(currentTime)
class _MoveAnimation(QPropertyAnimation):
    '''move animation'''

    MOVE1 = 1
    MOVE2 = 2
    MOVE3 = 3

    def __init__(self, target, parent, easing = QEasingCurve.Custom):
        super(_MoveAnimation, self).__init__(target, b"pos")
        self.parent = parent
        self.easing = easing
        if easing != -1:
            self.setEasingCurve(easing)
        self.m_path = QPainterPath()

    def setMoveType(self, _type):
        self._type = _type

    def updateCurrentTime(self, currentTime):
        if self.m_path.isEmpty():
            # end = self.endValue()
            start = self.startValue()
            if self._type == self.MOVE1:
                end = QPoint(self.parent.width() / 4.0, 0)
            elif self._type == self.MOVE2:
                end = QPoint((self.parent.width() / 4.0) * 3.0, 0)
                if not start:
                    start = QPoint(self.parent.width() / 4.0, 0)
                    # 第二个移动没有设置开始坐标,这里以第一个移动结束为开始
            elif self._type == self.MOVE3:
                if not start:
                    start = QPoint((self.parent.width() / 4.0) * 3.0, 0)
                    # 第三个移动没有设置开始坐标,这里以第二个移动结束为开始
                end = QPoint(self.parent.width(), 0)
            self.m_path.moveTo(start)
            self.m_path.addEllipse(QRectF(start, end))

        dura = self.duration()
        if dura == 0:
            progress = 1.0
        else:
            progress = (((currentTime - 1) % dura) + 1) / float(dura)

        easedProgress = self.easingCurve().valueForProgress(progress)
        if easedProgress > 1.0:
            easedProgress -= 1.0
        elif easedProgress < 0:
            easedProgress += 1.0

        pt = self.m_path.pointAtPercent(easedProgress)
        self.updateCurrentValue(pt)
        self.valueChanged.emit(pt)
        super(_MoveAnimation, self).updateCurrentTime(currentTime)
class _MpcbAnimation(QPropertyAnimation):

    def __init__(self, parent, target, index, easing = QEasingCurve.InQuad):
        super(_MpcbAnimation, self).__init__(target, b"pos")
        self.parent = parent
        self.m_pathType = 1
        self.easing = easing
        self.createAnimation(target, index)

    def createAnimation(self, target, index):
        '''创建动画'''
        self.m_path = QPainterPath()
        if self.easing != -1:
            self.setEasingCurve(self.easing)
        self.setStartValue(QPointF(0, 0))
        self.setEndValue(QPointF(90, 90))
        self.setDuration(2000)
        self.setLoopCount(-1)

    def updateCurrentTime(self, currentTime):
        if self.m_pathType:
            if self.m_path.isEmpty():
                end = self.endValue()
                start = self.startValue()
                self.m_path.moveTo(start)
                self.m_path.addEllipse(QRectF(start, end))

            dura = self.duration()
            if dura == 0:
                progress = 1.0
            else:
                progress = (((currentTime - 1) % dura) + 1) / float(dura)

            easedProgress = self.easingCurve().valueForProgress(progress)
            if easedProgress > 1.0:
                easedProgress -= 1.0
            elif easedProgress < 0:
                easedProgress += 1.0

            pt = self.m_path.pointAtPercent(easedProgress)
            self.updateCurrentValue(pt)
            self.valueChanged.emit(pt)
        else:
            super(_MpcbAnimation, self).updateCurrentTime(currentTime)
class _MpcbAnimation(QPropertyAnimation):
    def __init__(self, parent, target, index, easing=QEasingCurve.InQuad):
        super(_MpcbAnimation, self).__init__(target, b"pos")
        self.parent = parent
        self.m_pathType = 1
        self.easing = easing
        self.createAnimation(target, index)

    def createAnimation(self, target, index):
        '''创建动画'''
        self.m_path = QPainterPath()
        if self.easing != -1:
            self.setEasingCurve(self.easing)
        self.setStartValue(QPointF(0, 0))
        self.setEndValue(QPointF(90, 90))
        self.setDuration(2000)
        self.setLoopCount(-1)

    def updateCurrentTime(self, currentTime):
        if self.m_pathType:
            if self.m_path.isEmpty():
                end = self.endValue()
                start = self.startValue()
                self.m_path.moveTo(start)
                self.m_path.addEllipse(QRectF(start, end))

            dura = self.duration()
            if dura == 0:
                progress = 1.0
            else:
                progress = (((currentTime - 1) % dura) + 1) / float(dura)

            easedProgress = self.easingCurve().valueForProgress(progress)
            if easedProgress > 1.0:
                easedProgress -= 1.0
            elif easedProgress < 0:
                easedProgress += 1.0

            pt = self.m_path.pointAtPercent(easedProgress)
            self.updateCurrentValue(pt)
            self.valueChanged.emit(pt)
        else:
            super(_MpcbAnimation, self).updateCurrentTime(currentTime)
Exemple #7
0
class Animation(QPropertyAnimation):
    LinearPath, CirclePath = range(2)

    def __init__(self, target, prop):
        super(Animation, self).__init__(target, prop)

        self.setPathType(Animation.LinearPath)

    def setPathType(self, pathType):
        self.m_pathType = pathType
        self.m_path = QPainterPath()

    def updateCurrentTime(self, currentTime):
        if self.m_pathType == Animation.CirclePath:
            if self.m_path.isEmpty():
                end = self.endValue()
                start = self.startValue()
                self.m_path.moveTo(start)
                self.m_path.addEllipse(QRectF(start, end))

            dura = self.duration()
            if dura == 0:
                progress = 1.0
            else:
                progress = (((currentTime - 1) % dura) + 1) / float(dura)

            easedProgress = self.easingCurve().valueForProgress(progress)
            if easedProgress > 1.0:
                easedProgress -= 1.0
            elif easedProgress < 0:
                easedProgress += 1.0

            pt = self.m_path.pointAtPercent(easedProgress)
            self.updateCurrentValue(pt)
            self.valueChanged.emit(pt)
        else:
            super(Animation, self).updateCurrentTime(currentTime)
Exemple #8
0
class Animation(QPropertyAnimation):
    LinearPath, CirclePath = range(2)

    def __init__(self, target, prop):
        super(Animation, self).__init__(target, prop)

        self.setPathType(Animation.LinearPath)

    def setPathType(self, pathType):
        self.m_pathType = pathType
        self.m_path = QPainterPath()

    def updateCurrentTime(self, currentTime):
        if self.m_pathType == Animation.CirclePath:
            if self.m_path.isEmpty():
                end = self.endValue()
                start = self.startValue()
                self.m_path.moveTo(start)
                self.m_path.addEllipse(QRectF(start, end))

            dura = self.duration()
            if dura == 0:
                progress = 1.0
            else:
                progress = (((currentTime - 1) % dura) + 1) / float(dura)

            easedProgress = self.easingCurve().valueForProgress(progress)
            if easedProgress > 1.0:
                easedProgress -= 1.0
            elif easedProgress < 0:
                easedProgress += 1.0

            pt = self.m_path.pointAtPercent(easedProgress)
            self.updateCurrentValue(pt)
            self.valueChanged.emit(pt)
        else:
            super(Animation, self).updateCurrentTime(currentTime)
Exemple #9
0
class BorderItem(QGraphicsObject):
    def __init__(self,
                 scene,
                 view_scale,
                 shape,
                 transform=QTransform(),
                 parent=None):
        super(BorderItem, self).__init__(parent)
        self.setTransform(transform)

        self.shape = shape
        self._item_path = QPainterPath(QPoint(0, 0))
        self._pen = QPen()
        self._pen.setWidthF(adjust_pen_width(PEN_STANDARD_WIDTH, view_scale))

        # 设置蚂蚁线数据
        self._line_len = 4
        self._line_step = .2
        self._line_speed = 100
        self._line_color = Qt.black

        # 线条的长度
        self._dashes = 4
        # 空白长度
        self._spaces = 10
        self._dash_pattern = [self._line_len] * 20
        self._timer = QTimer()
        self._timer.timeout.connect(self.update_value)

        if scene:
            scene.clearSelection()
            scene.addItem(self)

    def is_empty(self):
        return self._item_path.isEmpty()

    def get_path(self):
        return self._item_path

    def get_scene_path(self):
        return self.mapToScene(self.get_path())

    def copy(self):
        new_item = SelectionItem(position=self.scenePos(),
                                 scene=None,
                                 view_scale=1,
                                 path=self._item_path,
                                 shape=self.get_shape(),
                                 transform=self.transform(),
                                 parent=self.parent())
        new_item.pen = self.pen
        return new_item

    def set_item_path_by_size(self, width=0, height=0):
        self._item_path = QPainterPath(QPoint(0, 0))
        self._item_path.addRect(QRectF(0, 0, width, height))
        self.update(self.boundingRect())

    def set_item_path_by_path(self, path):
        self._item_path = path

    def set_pen_width_by_scale(self, width: [int, float]):
        pen_width = adjust_pen_width(PEN_STANDARD_WIDTH, width)
        self._pen.setWidthF(pen_width)

    def set_pen_width_by_width(self, width: [int, float]):
        if isinstance(width, int):
            self._pen.setWidth(width)
        elif isinstance(width, float):
            self._pen.setWidthF(width)

    @property
    def pen(self):
        return self._pen

    @pen.setter
    def pen(self, new_pen: QPen):
        self._pen = new_pen

    def update_value(self):
        """"""
        if self._dashes >= self._line_len and self._spaces >= self._line_len:
            self._dashes = self._spaces = 0.

        if self._dashes <= 0 and self._spaces < self._line_len:
            self._spaces += self._line_step
        elif self._dashes < self._line_len <= self._spaces:
            self._dashes += self._line_step

        self._dash_pattern[0] = self._dashes
        self._dash_pattern[1] = self._spaces
        self.update(self.boundingRect())

    def add_area(self, path: QPainterPath):
        """TODO"""

    def cut_area(self, path: QPainterPath):
        """TODO"""

    def combine_area(self, path: QPainterPath):
        """TODO"""

    def intersects(self, other) -> bool:
        p1 = self.mapToScene(self.get_path())
        p2 = other.mapToScene(other.get_path())
        return p1.intersects(p2)

    def shape(self):
        return self._item_path

    # 继承QGraphicsItem类必须实现 boundingRect() paint()两个方法
    # 返回本item的 包围和矩形 QRectF 用于item的点击等判断
    def boundingRect(self):
        return self._item_path.boundingRect().adjusted(0, 0, 2, 2)

    def paint(self, painter: QPainter, option, widget=None) -> None:

        self._pen.setColor(Qt.white)
        self._pen.setStyle(Qt.SolidLine)
        painter.setPen(self._pen)
        painter.drawPath(self._item_path)

        self._pen.setColor(Qt.black)
        self._pen.setDashPattern(self._dash_pattern)
        painter.setPen(self._pen)
        painter.drawPath(self._item_path)

    def __add__(self, other):
        """
        轮廓 +operation
        :param other:
        :return: self
        """
        p1 = self.mapToScene(self._item_path)
        p2 = other.mapToScene(other.get_path())
        new_path = self.mapFromScene(p1 + p2)

        new_item = self.copy()
        new_item.set_item_path_by_path(new_path)
        return new_item

    def __iadd__(self, other):
        """
        轮廓 +=operation
        :param other:
        :return: self
        """
        p1 = self.mapToScene(self._item_path)
        p2 = other.mapToScene(other.get_path())
        new_path = self.mapFromScene(p1 + p2)
        new_path.closeSubpath()
        self._item_path = new_path
        return self

    def __sub__(self, other):
        """
        轮廓 -operation
        :param other:
        :return: self
        """
        p1 = self.mapToScene(self._item_path)
        p2 = other.mapToScene(other.get_path())
        new_path = self.mapFromScene(p1 - p2)
        new_path.closeSubpath()

        new_item = self.copy()
        new_item.set_item_path_by_path(new_path)
        return new_item

    def __isub__(self, other):
        """
        轮廓 -=operation
        :param other:
        :return: self
        """
        p1 = self.mapToScene(self._item_path)
        p2 = other.mapToScene(other.get_path())
        new_path = self.mapFromScene(p1 - p2)
        new_path.closeSubpath()
        self._item_path = new_path
        self.update()
        return self

    def __and__(self, other):
        """
        轮廓 &operation
        :param other:
        :return: self
        """
        p1 = self.mapToScene(self._item_path)
        p2 = other.mapToScene(other.get_path())
        new_path = self.mapFromScene(p1 & p2)
        new_path.closeSubpath()

        new_item = self.copy()
        new_item.set_item_path_by_path(new_path)
        return new_item

    def __iand__(self, other):
        """
        轮廓 &=operation
        :param other:
        :return: self
        """
        p1 = self.mapToScene(self._item_path)
        p2 = other.mapToScene(other.get_path())
        self._item_path = self.mapFromScene(p1 & p2)
        self._item_path.closeSubpath()
        self.update()
        return self
Exemple #10
0
class GraphicsPathObject(QGraphicsObject):
    """A QGraphicsObject subclass implementing an interface similar to
    QGraphicsPathItem, and also adding a positionChanged() signal

    """

    positionChanged = Signal([], ["QPointF"])

    def __init__(self, parent=None, **kwargs):
        QGraphicsObject.__init__(self, parent, **kwargs)
        self.setFlag(QGraphicsObject.ItemSendsGeometryChanges)

        self.__path = QPainterPath()
        self.__brush = QBrush(Qt.NoBrush)
        self.__pen = QPen()
        self.__boundingRect = None

    def setPath(self, path):
        """Set the items `path` (:class:`QPainterPath`).
        """
        if not isinstance(path, QPainterPath):
            raise TypeError("%r, 'QPainterPath' expected" % type(path))

        if self.__path != path:
            self.prepareGeometryChange()
            # Need to store a copy of object so the shape can't be mutated
            # without properly updating the geometry.
            self.__path = QPainterPath(path)
            self.__boundingRect = None
            self.update()

    def path(self):
        """Return the items path.
        """
        return QPainterPath(self.__path)

    def setBrush(self, brush):
        """Set the items `brush` (:class:`QBrush`)
        """
        if not isinstance(brush, QBrush):
            brush = QBrush(brush)

        if self.__brush != brush:
            self.__brush = QBrush(brush)
            self.update()

    def brush(self):
        """Return the items brush.
        """
        return QBrush(self.__brush)

    def setPen(self, pen):
        """Set the items outline `pen` (:class:`QPen`).
        """
        if not isinstance(pen, QPen):
            pen = QPen(pen)

        if self.__pen != pen:
            self.prepareGeometryChange()
            self.__pen = QPen(pen)
            self.__boundingRect = None
            self.update()

    def pen(self):
        """Return the items pen.
        """
        return QPen(self.__pen)

    def paint(self, painter, option, widget=None):
        if self.__path.isEmpty():
            return

        painter.save()
        painter.setPen(self.__pen)
        painter.setBrush(self.__brush)
        painter.drawPath(self.__path)
        painter.restore()

    def boundingRect(self):
        if self.__boundingRect is None:
            br = self.__path.controlPointRect()
            pen_w = self.__pen.widthF()
            self.__boundingRect = br.adjusted(-pen_w, -pen_w, pen_w, pen_w)

        return self.__boundingRect

    def shape(self):
        return shapeFromPath(self.__path, self.__pen)

    def itemChange(self, change, value):
        if change == QGraphicsObject.ItemPositionHasChanged:
            pos = qunwrap(value)
            self.positionChanged.emit()
            self.positionChanged[QPointF].emit(pos)

        return QGraphicsObject.itemChange(self, change, value)