1. 结论
今天才知道,改变图元的位置的两个方法:
setPos()
和
transform.translate()
的本质是不同的!
2. 缘由
在调试代码时,获取某个位置不在原点的图元的坐标总是返回(0,0),百思不得其解,后仔细研究发现。该图元使用的是
transform.translate(x, y)
对图元进行的平移,难道这和 setPos() 函数并不是等效?我使用
【PyQt】运行QGraphicsItem的Demo代码及三个坐标系的基础用法讲解_pyqt qgraphic 父坐标_qilei2010的博客-CSDN博客
文章中的Demo代码进行了测试,发现二者果然不同。
3. 实验
核心代码如下:
# 1. 通过setPos() 设置图元位置
item = MyItem() # 默认的绿色半透明
item.setPos(10,10)
self.scene.addItem(item)
print(item.pos().x()) # 输出 10
# 2. 通过设置 translate() 平移图元
item2 = MyItem()
item2.BrushColor = QColor(231, 55, 55, 127) # 红色半透明
tf = QTransform()
tf.translate(20,20) # 平移 20,20
item2.setTransform(tf)
self.scene.addItem(item2)
print(item2.pos().x()) # 输出 0
输出:
神奇的结果出现了。
使用
transform.translate(x, y)
将图元向右下方平移了20像素,再返回图元的 pos() 居然依然是 (0,0 )。
可以理解为:
transform.translate(x, y)
函数的效果是改变了图元本身的几何特性(平移、变形、缩放),而并非设置图元在父对象中的位置。
看Qt官方对 QTransform 的说明:
The QTransform class specifies 2D transformations of a coordinate system.
A transformation specifies how to translate, scale, shear, rotate or project the coordinate system, and is typically used when rendering graphics.
QTransform类约定了坐标系统的2D变换。
它约定了如何平移、缩放、错切/斜切、旋转或投影坐标系统,主要用来渲染图形元素。
可以理解为是对图元的坐标系统的改变,而不是对图元在父对象或者场景中的位置的改变。
二者不同,但是展示出的图形效果是一样的。
完整代码:
# *******************************************************************************
# * Copyright (c) 2022, <hi_qilei@qq.com><https://blog.csdn.net/qilei2010>
# * update at 2023.01.05 by <hi_qilei@qq.com><https://blog.csdn.net/qilei2010>
# *******************************************************************************
# """ test qt5 example demo , [pycharm, pyqt5, win10]"""
import sys
from PyQt5.QtGui import QPainterPath, QColor, QPen, QTransform
from PyQt5.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QMainWindow, QGraphicsItem
from PyQt5.QtCore import Qt, QRectF, QLineF, QPointF
# 自定义图元
class MyItem(QGraphicsItem):
def __init__(self):
super().__init__()
self.BrushColor = QColor(30, 215, 109, 127) # 默认颜色,半透明绿色。RGBA,127指透明度
# 必须实现的两个方法 painter 和 boundingRect
def paint(self, painter, option, widget):
# 这里可以替换为你要测试的代码
path = QPainterPath()
path.addRect(0, 0, 50, 50) # 矩形,左上角坐标为(0,0),长度30,宽度30
painter.setBrush(self.BrushColor) # 设置画刷颜色-用于填充颜色,
painter.drawPath(path) # 绘制path
def boundingRect(self):
return QRectF(0, 0, 50, 50) # 图元边界,用于scene刷新图元
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.scene = QGraphicsScene()
# 1. 通过setPos() 设置图元位置
item = MyItem() # 默认的绿色半透明
item.setPos(10,10)
self.scene.addItem(item)
print(item.pos().x()) # 输出 10
# # 1. 通过设置 translate() 平移图元
item2 = MyItem()
item2.BrushColor = QColor(231, 55, 55, 127) # 红色半透明
tf = QTransform()
tf.translate(20,20) # 平移 10,10
item2.setTransform(tf)
self.scene.addItem(item2)
print(item2.pos().x()) # 输出 0
# 有view就要有scene
self.view = QGraphicsView()
self.view.setScene(self.scene)
# 设置场景中心点为(0,0),绘制坐标为(0,0)的图元会出现在窗口的正中心,方便新手绘制图元
self.view.scene().setSceneRect(-100, -100, 200, 200) # 场景的左上角为(-100,100)宽200高200
# 绘制xOy直角坐标系x、y坐标轴,方便新手
self.view.scene().setBackgroundBrush(QColor("white")) # 设置场景scene背景色为灰色
self.view.scene().addLine(QLineF(QPointF(-100, 0), QPointF(100, 0))) # x轴线
self.view.scene().addLine(QLineF(QPointF(0, -100), QPointF(0, 100))) # y轴线
# 设置view可以进行鼠标的拖拽选择
self.view.setDragMode(self.view.RubberBandDrag)
self.setMinimumHeight(400) # 窗口最小高度
self.setMinimumWidth(400) # 窗口最小宽度
self.setCentralWidget(self.view)
self.setWindowTitle("Graphics Demo")
def demo_run():
app = QApplication(sys.argv)
demo = MainWindow()
# 适配 Retina 显示屏(选写).
app.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
app.setAttribute(Qt.AA_EnableHighDpiScaling, True)
# ----------------------------------
demo.show()
sys.exit(app.exec_())
if __name__ == '__main__':
demo_run()
<全文完>