如何检索场景中 QGraphicsPixmapItem 的 QGraphicsRectItem 坐标?

How to retrieve QGraphicsRectItem coordinate with respect to a QGraphicsPixmapItem on a scene?

检索场景中 QGraphicsRectItem 相对于 QGraphicsPixmapItem 坐标的最佳方法是什么?

这是我的主要代码 window class。

import sys
from PySide2 import QtCore, QtGui
from PySide2.QtWidgets import *
from PySide2.QtGui import QBrush, QPen

class main_window(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(100, 100, 500, 500)

        self.rect = ResizableRect(100, 100, 100, 100)
        self.rect.setZValue(1)
        self.rect.setRotation(10)

        self.view = QGraphicsView(self)
        self.scene = QGraphicsScene(self.view)
        self.scene.addItem(self.rect)

        pixmap = QtGui.QPixmap("images/sadcat.jpg")
        pixmap_item = self.scene.addPixmap(pixmap)
        pixmap_item.setPixmap(pixmap)

        self.view.setSceneRect(0, 0, 500,500)
        self.view.setScene(self.scene)

        self.slider = QSlider(QtCore.Qt.Horizontal)
        self.slider.setMinimum(0)
        self.slider.setMaximum(90)

        vbox = QVBoxLayout(self)
        vbox.addWidget(self.view)
        vbox.addWidget(self.slider)

        self.setLayout(vbox)

        self.slider.valueChanged.connect(self.rotate)

    def rotate(self, value):
        self.angle = int(value)
        self.rect.setRotation(self.angle)

这是自定义 QGraphicsRectItem 的代码(感谢

class ResizableRect(QGraphicsRectItem):
    def __init__(self, *args):
        super().__init__(*args)
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges, True)
        self.setPen(QPen(QBrush(QtGui.QColor('red')), 5))
        self.selected_edge = None
        self.first_pos = self.click_rect = None

    def mousePressEvent(self, event):
        """ The mouse is pressed, start tracking movement. """
        self.first_pos = event.pos()
 
        self.rect_shape = self.rect()

        if abs(self.rect_shape.left() - self.first_pos.x()) < 5:
            self.selected_edge = 'left'
        elif abs(self.rect_shape.right() - self.first_pos.x()) < 5:
            self.selected_edge = 'right'
        elif abs(self.rect_shape.top() - self.first_pos.y()) < 5:
            self.selected_edge = 'top'
        elif abs(self.rect_shape.bottom() - self.first_pos.y()) < 5:
            self.selected_edge = 'bottom'
        else:
            self.selected_edge = None
        self.first_pos = event.pos()
        self.click_rect = self.rect_shape
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        """ Continue tracking movement while the mouse is pressed. """
        # Calculate how much the mouse has moved since the click.
        self.pos = event.pos()
        x_diff = self.pos.x() - self.first_pos.x()
        y_diff = self.pos.y() - self.first_pos.y()

        # Start with the rectangle as it was when clicked.
        self.rect_shape = QtCore.QRectF(self.click_rect)

        # Then adjust by the distance the mouse moved.
        if self.selected_edge is None:
            self.rect_shape.translate(x_diff, y_diff)
        elif self.selected_edge == 'top':
            self.rect_shape.adjust(0, y_diff, 0, 0)
        elif self.selected_edge == 'left':
            self.rect_shape.adjust(x_diff, 0, 0, 0)
        elif self.selected_edge == 'bottom':
            self.rect_shape.adjust(0, 0, 0, y_diff)
        elif self.selected_edge == 'right':
            self.rect_shape.adjust(0, 0, x_diff, 0)

        self.setRect(self.rect_shape)
        coor = self.rect_shape.getRect()
        self.setTransformOriginPoint(coor[0] + coor[2]/2, coor[1] + coor[3]/2)

        print(coor)

主要 window GUI 如下所示。

Qt 图形框架处理几个坐标系:

  • 相对于现场
  • 相对于视口。
  • 关于任何项目。

并且 QGraphicsView、QGraphicsScene 和 QGraphicsItems 具有允许在各种类型的坐标系之间进行转换的方法。

一般的实现是将相对于X的任意位置转换为场景的坐标,然后再转换相对于Y的坐标。

还应该知道,场景和物品的坐标是浮点数:QPointFQRectFQPolygonF但可以转换为整数值分别使用 toPoint()toRect()toPolygon() 方法。

所以在这种情况下,您可以将QGraphicsRectItem的boundingRect()相对于item转换为场景坐标,然后将它们相对于QGraphicsPixmapItem转换:

import random
from PySide2 import QtCore, QtGui, QtWidgets


def build_pixmap():
    pixmap = QtGui.QPixmap(400, 400)
    pixmap.fill(QtCore.Qt.transparent)

    painter = QtGui.QPainter(pixmap)
    painter.setRenderHints(
        QtGui.QPainter.Antialiasing | QtGui.QPainter.SmoothPixmapTransform
    )
    painter.setPen(QtCore.Qt.NoPen)
    for _ in range(100):
        x, y = random.sample(range(-100, 400), 2)
        color = QtGui.QColor(*random.sample(range(255), 3))
        painter.setBrush(color)
        painter.drawEllipse(QtCore.QRect(0, 0, 100, 100).translated(x, y))

    painter.end()
    return pixmap


def main():
    app = QtWidgets.QApplication()

    scene = QtWidgets.QGraphicsScene()
    view = QtWidgets.QGraphicsView(
        scene,
        renderHints=QtGui.QPainter.Antialiasing | QtGui.QPainter.SmoothPixmapTransform,
    )

    rect_item = QtWidgets.QGraphicsRectItem()
    rect_item.setPen(QtGui.QPen(QtGui.QColor("red"), 5))
    rect_item.setBrush(QtGui.QColor("gray"))
    rect_item.setRect(QtCore.QRectF(-30, -40, 100, 200))
    rect_item.setPos(QtCore.QPointF(170, 150))
    rect_item.setTransformOriginPoint(30, 20)
    rect_item.setRotation(30)

    pixmap_item = QtWidgets.QGraphicsPixmapItem()
    pixmap_item.setPixmap(build_pixmap())

    scene.addItem(pixmap_item)
    scene.addItem(rect_item)

    scene_coordinate = rect_item.mapToScene(rect_item.boundingRect())
    # view_coordinate = view.mapFromScene(scene_coordinate)
    pixmap_coordinate = pixmap_item.mapFromScene(scene_coordinate)
    for point in pixmap_coordinate.toPolygon():
        print(point)

    view.resize(640, 480)
    view.show()

    app.exec_()


if __name__ == "__main__":
    main()

输出:

PySide2.QtCore.QPoint(177, 85)
PySide2.QtCore.QPoint(268, 137)
PySide2.QtCore.QPoint(166, 315)
PySide2.QtCore.QPoint(75, 262)
PySide2.QtCore.QPoint(177, 85)