mapToScene要求显示视图以进行正确的转换?

2024-09-29 00:15:33 发布

您现在位置:Python中文网/ 问答频道 /正文

主要问题:根据是否显示GUI,QGraphicsView.mapToScene方法返回不同的答案。为什么,我能绕开它吗?

上下文是我正在尝试编写单元测试,但我不想实际显示测试工具。在

下面的小例子说明了这种行为。我使用一个子类视图,通过调用mapToScene,在场景坐标系中打印鼠标单击事件的位置,原点位于左下角(垂直比例为-1)。但是,mapToScene在显示对话框之前没有返回我期望的结果。如果运行底部的main部分,会得到以下输出:

Size is (150, 200)
Putting in (50, 125) - This point should return (50.0, 75.0)
Before show(): PyQt5.QtCore.QPointF(84.0, -20.0)
After show() : PyQt5.QtCore.QPointF(50.0, 75.0)

show()之前,x上有34个像素的一致偏移量,y方向有105个像素点的偏移量(在y轴上偏移量反向移动,就好像没有应用比例一样)。这些偏移量看起来很随机,我不知道它们是从哪里来的。在

下面是示例代码:

^{pr2}$

这个例子在Windows上的PyQt5中,但是在Linux上的PyQt4也有同样的作用。在


Tags: 方法答案show测试工具gui单元测试子类pyqt5
2条回答

跳入C++ QT源代码时,QQ:Q/P>>

QPointF QGraphicsView::mapToScene(const QPoint &point) const
{
    Q_D(const QGraphicsView);
    QPointF p = point;
    p.rx() += d->horizontalScroll();
    p.ry() += d->verticalScroll();
    return d->identityMatrix ? p : d->matrix.inverted().map(p);
}

关键的是p.rx() += d->horizontalScroll();和垂直滚动。QGraphicsView始终包含滚动条,即使它们总是关闭或不显示。在显示小部件之前观察到的偏移量来自初始化时水平和垂直滚动条的值,当显示小部件和计算布局时,必须修改这些值以匹配视图/视口。为了使mapToScene正常工作,必须设置滚动条以匹配场景/视图。在

如果我把下面几行放在示例中对mapToScene的调用之前,那么我将得到适当的转换结果,而不必显示小部件。在

^{pr2}$

要更一般地执行此操作,可以从视图中提取一些相关的转换。在

# Use the size hint to get shape info
wid, hgt = (pick.view.sizeHint().width()-2,
            pick.view.sizeHint().height()-2) # -2 removes padding ... maybe?

# Get the opposing corners through the view transformation
px = pick.view.transform().map(QPoint(wid, 0))
py = pick.view.transform().map(QPoint(0, hgt))

# Set the scroll bars accordingly
pick.view.horizontalScrollBar().setRange(px.y(), px.x())
pick.view.verticalScrollBar().setRange(py.y(), py.x())
pick.view.horizontalScrollBar().setValue(px.y())
pick.view.verticalScrollBar().setValue(py.y())

这是一个既老套又难看的解决方案,因此,虽然它确实有效,但可能有一种更优雅的方法来处理这个问题。在

您是否尝试过实现自己的qgraphicsview并重写resizeEvent?当您在mapTo“something”中捣乱时,您必须处理好您的resizeEvents,请看一下我从您的代码中提取并稍加修改的代码>

from PyQt5.QtCore import QRectF
from PyQt5.QtWidgets import (QGraphicsScene, QGraphicsView, QVBoxLayout,
                             QApplication, QFrame, QSizePolicy)
from PyQt5.QtCore import QPoint


class GraphicsView(QGraphicsView):

    def __init__(self):
        super(GraphicsView, self).__init__()


        # Scene and view
        scene = QGraphicsScene(0, 0, 150, 200,)
        scene.setSceneRect(0, 0, 150, 200)


    def resizeEvent(self, QResizeEvent):
        self.setSceneRect(QRectF(self.viewport().rect()))

qapp = QApplication(['python'])

# Just something to be a parent

view = GraphicsView()


# Short layout


# Make a test point
p0 = QPoint(50, 125)

# Pass in the test point before and after
print("Passing in point: ", p0)
print("Received point before show:", view.mapToScene(p0))
view.show()
print("Received point after show:", view.mapToScene(p0))

qapp.exec_()

这是你想要的行为吗?”)

相关问题 更多 >