Qt / SVG - 获取元素的准确坐标

Qt / SVG - getting accurate coordinates of element

我正在使用 Qt,试图制作一个“可点击的 SVG”小部件的原型。我正在尝试从 QSvgWidget.

获取 SVG 中特定元素的准确坐标

为了弄清楚如何做到这一点,我有以下非常粗略的代码。我想要做的是以编程方式让“foo”QLabel 与显示的 SVG 中的“foo”矩形具有相同的位置。

from PySide2.QtWidgets import QApplication, QWidget, QLabel, QMainWindow
from PySide2.QtSvg import QSvgWidget
from PySide2.QtCore import QTimer

import sys

app = QApplication(sys.argv)

window = QMainWindow()

central = QSvgWidget("test_svg.svg")
foo = QLabel("foo", parent=central)

window.setCentralWidget(central)

bound1 = central.renderer().boundsOnElement("foo")
bound2 = central.renderer().transformForElement("foo").mapRect(bound1)
tl = bound2.topLeft()
foo.move(tl.x(), tl.y())

window.show()

app.exec_()

这是 SVG:

<svg height="400" width="450" viewbox="0 0 450 400" xmlns="http://www.w3.org/2000/svg">
<circle stroke="red" fill="none" cx="50" cy="50" r="30" />
<rect id="foo" stroke="blue" fill="none" x="100" y="300" width="20" height="5" />
</svg>

这是我在屏幕上看到的内容:

当我调试发生的事情时,我看到 bound1.topLeft()bound2.topLeft() 相同,并且等于 PySide2.QtCore.QPointF(99.500000, 299.500000)。这几乎是“foo”元素在 SVG 坐标中的位置。

我不确定正确的术语是什么,但让我将 SVG 坐标系 定义为 SVG 文件中使用的坐标系和 小部件坐标系 作为对应于实际像素位置的坐标系,其中某些内容相对于相关小部件的左上角以像素呈现。

所以 QSvgWidget 似乎给我 SVG 坐标而不是“小部件坐标”。

有谁知道我是否有一种规范的方法让 Qt 为我提供针对这些目的“准确”的坐标?我可能可以通过使用小部件大小来计算比例因子等来解决这个问题,但 Qt 似乎有比这更好的方法。毕竟,在某些时候 Qt 必须知道实际缩放坐标才能进行渲染。

看看: https://github.com/qt/qtsvg/blob/52d3788c7b0116ea3db232dccca5f1e3f1e229ac/src/svg/qsvgrenderer.cpp#L418

渲染器是: https://github.com/qt/qtsvg/blob/52d3788c7b0116ea3db232dccca5f1e3f1e229ac/src/svg/qsvgrenderer.cpp#L120

所以我们转到 QSvgTinyDocument 的渲染实现: https://github.com/qt/qtsvg/blob/5.15.2/src/svg/qsvgtinydocument.cpp#L311

然后进行相关方法: https://github.com/qt/qtsvg/blob/5.15.2/src/svg/qsvgtinydocument.cpp#L462

...
        if (m_implicitViewBox || !preserveAspectRatio()) {
...
            QTransform transform;
            transform.scale(target.width() / source.width(),
                            target.height() / source.height());
            QRectF c2 = transform.mapRect(source);
...

因此 target 是像素坐标中要绘制的目标表面的矩形,source 是 SVG 坐标驱动的 SVG 源。 在我看来,您首先猜测计算从 SVG 坐标到绝对像素坐标的系数正是 Qt 在内部所做的。

相关 QPainter 存储有关从 SVG 坐标到像素的转换信息,然后用于从 SVG 绘制实际像素,但据我所知你不能不应该访问像这样的深层内部框架状态。猜猜你首先假设计算比例系数是你应该做的。

请注意,在 Qt::KeepAspectRatio 模式的情况下,事情可能会变得更加麻烦,SVG 将居中并在小部件目标表面允许的范围内缩放,同时保持纵横比相同。 看起来这种情况在 Qt 5.15 中是可能的: https://github.com/qt/qtsvg/blob/52d3788c7b0116ea3db232dccca5f1e3f1e229ac/src/svg/qsvgtinydocument.cpp#L474

https://doc.qt.io/qt-5/qsvgrenderer.html#aspectRatioMode-prop

我已将您的示例修改(非常快速地修改)为: