【问题标题】:Resize about center on a QGraphicsItem proportional to mouse speed?调整与鼠标速度成比例的 QGraphicsItem 中心的大小?
【发布时间】:2020-06-02 21:15:09
【问题描述】:

我很抱歉反复询问有关 pyqt 的问题,但它的有限资源迫使我这样做。

我一直在尝试为我的圆形实现一个调整大小的功能,它是 QGraphicsItem 的扩展,它有一个椭圆和一个居中的文本。我可以根据需要调整形状的大小,但是形状需要一段时间才能赶上鼠标,即在切换方向时,圆圈会继续增加,但需要一段时间来切换方向,此外,圆圈会在顶部使用锚点调整大小边界矩形的左角。

代码背景见this question

def updateHandlesPos(self):
        s = self.handleSize
        b = self.boundingRect()
        self.handles[self.handleTopLeft] = QRectF(b.left(), b.top(), s, s)
        self.handles[self.handleTopMiddle] = QRectF(b.center().x() - s / 2, b.top(), s, s)
        self.handles[self.handleTopRight] = QRectF(b.right() - s, b.top(), s, s)
        self.handles[self.handleMiddleLeft] = QRectF(b.left(), b.center().y() - s / 2, s, s)
        self.handles[self.handleMiddleRight] = QRectF(b.right() - s, b.center().y() - s / 2, s, s)
        self.handles[self.handleBottomLeft] = QRectF(b.left(), b.bottom() - s, s, s)
        self.handles[self.handleBottomMiddle] = QRectF(b.center().x() - s / 2, b.bottom() - s, s, s)
        self.handles[self.handleBottomRight] = QRectF(b.right() - s, b.bottom() - s, s, s)

    def interactiveResize(self, mousePos):
        self.prepareGeometryChange()
        if self.handleSelected in [self.handleTopLeft,
                                   self.handleTopRight,
                                   self.handleBottomLeft,
                                   self.handleBottomRight,
                                   self.handleTopMiddle,
                                   self.handleBottomMiddle,
                                   self.handleMiddleLeft,
                                   self.handleMiddleRight]:
            self.radius += (mousePos.y() + mousePos.x() + self.mousePressPos.x() - self.mousePressPos.y())/64
            self.setPos(self.x(),self.y())
        self.update()   
        self.updateHandlesPos()

【问题讨论】:

    标签: python python-3.x pyqt pyqt5 qgraphicsitem


    【解决方案1】:

    由于 OP 没有提供 MRE,所以我从头开始创建了一个示例。其逻辑是跟踪项目的变化,并据此计算新的几何形状并确定其他项目的新位置。

    from PyQt5 import QtWidgets, QtGui, QtCore
    
    
    class GripItem(QtWidgets.QGraphicsPathItem):
        circle = QtGui.QPainterPath()
        circle.addEllipse(QtCore.QRectF(-5, -5, 10, 10))
        square = QtGui.QPainterPath()
        square.addRect(QtCore.QRectF(-10, -10, 20, 20))
    
        def __init__(self, annotation_item, index):
            super(GripItem, self).__init__()
            self.m_annotation_item = annotation_item
            self.m_index = index
    
            self.setPath(GripItem.circle)
            self.setBrush(QtGui.QColor("green"))
            self.setPen(QtGui.QPen(QtGui.QColor("green"), 2))
            self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True)
            self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
            self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges, True)
            self.setAcceptHoverEvents(True)
            self.setZValue(11)
            self.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
    
        def hoverEnterEvent(self, event):
            self.setPath(GripItem.square)
            self.setBrush(QtGui.QColor("red"))
            super(GripItem, self).hoverEnterEvent(event)
    
        def hoverLeaveEvent(self, event):
            self.setPath(GripItem.circle)
            self.setBrush(QtGui.QColor("green"))
            super(GripItem, self).hoverLeaveEvent(event)
    
        def mouseReleaseEvent(self, event):
            self.setSelected(False)
            super(GripItem, self).mouseReleaseEvent(event)
    
        def itemChange(self, change, value):
            if change == QtWidgets.QGraphicsItem.ItemPositionChange and self.isEnabled():
                self.m_annotation_item.movePoint(self.m_index, value)
            return super(GripItem, self).itemChange(change, value)
    
    
    class DirectionGripItem(GripItem):
        def __init__(self, annotation_item, direction=QtCore.Qt.Horizontal, parent=None):
            super(DirectionGripItem, self).__init__(annotation_item, parent)
            self._direction = direction
    
        @property
        def direction(self):
            return self._direction
    
        def itemChange(self, change, value):
            if change == QtWidgets.QGraphicsItem.ItemPositionChange and self.isEnabled():
                p = QtCore.QPointF(self.pos())
                if self.direction == QtCore.Qt.Horizontal:
                    p.setX(value.x())
                elif self.direction == QtCore.Qt.Vertical:
                    p.setY(value.y())
                self.m_annotation_item.movePoint(self.m_index, p)
                return p
            return super(DirectionGripItem, self).itemChange(change, value)
    
    
    class CircleAnnotation(QtWidgets.QGraphicsEllipseItem):
        def __init__(self, radius=1, parent=None):
            super(CircleAnnotation, self).__init__(parent)
            self.setZValue(11)
            self.m_items = []
    
            self.setPen(QtGui.QPen(QtGui.QColor("green"), 4))
    
            self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True)
            self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
            self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges, True)
    
            self.setAcceptHoverEvents(True)
    
            self.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
    
            self._radius = radius
            self.update_rect()
    
        @property
        def radius(self):
            return self._radius
    
        @radius.setter
        def radius(self, r):
            if r <= 0:
                raise ValueError("radius must be positive")
            self._radius = r
            self.update_rect()
            self.add_grip_items()
            self.update_items_positions()
    
        def update_rect(self):
            rect = QtCore.QRectF(0, 0, 2 * self.radius, 2 * self.radius)
            rect.moveCenter(self.rect().center())
            self.setRect(rect)
    
        def add_grip_items(self):
            if self.scene() and not self.m_items:
                for i, (direction) in enumerate(
                    (
                        QtCore.Qt.Vertical,
                        QtCore.Qt.Horizontal,
                        QtCore.Qt.Vertical,
                        QtCore.Qt.Horizontal,
                    )
                ):
                    item = DirectionGripItem(self, direction, i)
                    self.scene().addItem(item)
                    self.m_items.append(item)
    
        def movePoint(self, i, p):
            if 0 <= i < min(4, len(self.m_items)):
                item_selected = self.m_items[i]
                lp = self.mapFromScene(p)
                self._radius = (lp - self.rect().center()).manhattanLength()
                k = self.indexOf(lp)
                if k is not None:
                    self.m_items = [item for item in self.m_items if not item.isSelected()]
                    self.m_items.insert(k, item_selected)
                    self.update_items_positions([k])
                    self.update_rect()
    
        def update_items_positions(self, index_no_updates=None):
            index_no_updates = index_no_updates or []
            for i, (item, direction) in enumerate(
                zip(
                    self.m_items,
                    (
                        QtCore.Qt.Vertical,
                        QtCore.Qt.Horizontal,
                        QtCore.Qt.Vertical,
                        QtCore.Qt.Horizontal,
                    ),
                ),
            ):
                item.m_index = i
                if i not in index_no_updates:
                    pos = self.mapToScene(self.point(i))
                    item = self.m_items[i]
                    item._direction = direction
                    item.setEnabled(False)
                    item.setPos(pos)
                    item.setEnabled(True)
    
        def indexOf(self, p):
            for i in range(4):
                if p == self.point(i):
                    return i
    
        def point(self, index):
            if 0 <= index < 4:
                return [
                    QtCore.QPointF(0, -self.radius),
                    QtCore.QPointF(self.radius, 0),
                    QtCore.QPointF(0, self.radius),
                    QtCore.QPointF(-self.radius, 0),
                ][index]
    
        def itemChange(self, change, value):
            if change == QtWidgets.QGraphicsItem.ItemPositionHasChanged:
                self.update_items_positions()
                return
            if change == QtWidgets.QGraphicsItem.ItemSceneHasChanged:
                self.add_grip_items()
                self.update_items_positions()
                return
            return super(CircleAnnotation, self).itemChange(change, value)
    
        def hoverEnterEvent(self, event):
            self.setBrush(QtGui.QColor(255, 0, 0, 100))
            super(CircleAnnotation, self).hoverEnterEvent(event)
    
        def hoverLeaveEvent(self, event):
            self.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
            super(CircleAnnotation, self).hoverLeaveEvent(event)
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
    
        scene = QtWidgets.QGraphicsScene()
        view = QtWidgets.QGraphicsView(scene)
        view.setRenderHints(QtGui.QPainter.Antialiasing)
        item = CircleAnnotation()
        item.radius = 100
        scene.addItem(item)
        view.showMaximized()
    
        sys.exit(app.exec_())
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-01
      • 2021-02-28
      • 2012-07-09
      • 1970-01-01
      • 1970-01-01
      • 2011-12-14
      • 2014-08-01
      • 2014-11-02
      相关资源
      最近更新 更多