调整与鼠标速度成正比的 QGraphicsItem 的中心大小? [英] Resize about center on a QGraphicsItem proportional to mouse speed?

查看:60
本文介绍了调整与鼠标速度成正比的 QGraphicsItem 的中心大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很抱歉重复询问有关 pyqt 的问题,但由于资源有限,我不得不这样做.

I am sorry for repetitively asking questions regarding pyqt, but the limited resources on it force me to.

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

I have been trying to implement a resize function for my circle shape, that is an extension of QGraphicsItem, which has an ellipse and a centered text. I am able to resize my shape as desired, but the shape takes a while to catch up to the mouse, i.e on switching directions the circle continues to increase but takes a while to switch directions, moreover the circle resizes with an anchor at the top left corner of the bounding rect.

请参阅这个问题了解一些代码背景

See this question for a bit of code background

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()

推荐答案

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

Since the OP has not provided an MRE then I have created an example from scratch. The logic is to track the changes of the items and according to that calculate the new geometry and establish the new position of the other items.

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_())

这篇关于调整与鼠标速度成正比的 QGraphicsItem 的中心大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆