如何检索场景中 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的坐标。
还应该知道,场景和物品的坐标是浮点数:QPointF
、QRectF
和QPolygonF
但可以转换为整数值分别使用 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)
检索场景中 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的坐标。
还应该知道,场景和物品的坐标是浮点数:QPointF
、QRectF
和QPolygonF
但可以转换为整数值分别使用 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)