【PyQt】QGraphicsItem的setPos和transformation的平移并不等效

16 篇文章 3 订阅

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

<全文完>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qilei2010

送我一张彩票中了平分

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值