gpt4 book ai didi

python - mapToScene 需要显示正确转换的 View 吗?

转载 作者:太空狗 更新时间:2023-10-29 17:08:32 26 4
gpt4 key购买 nike

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

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

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

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 中偏移反向移动,就好像没有应用比例一样)。这些偏移量看起来相当随机,我不知道它们来自哪里。

示例代码如下:

import numpy as np
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QPointF, QPoint
from PyQt5.QtWidgets import (QDialog, QGraphicsView, QGraphicsScene,
QVBoxLayout, QPushButton, QApplication,
QSizePolicy)
from PyQt5.QtGui import QPixmap, QImage

class MyView(QGraphicsView):
"""View subclass that emits mouse events in the scene coordinates."""

mousedown = pyqtSignal(QPointF)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

self.setSizePolicy(QSizePolicy.Fixed,
QSizePolicy.Fixed)

# This is the key thing I need
self.scale(1, -1)

def mousePressEvent(self, event):
return self.mousedown.emit(self.mapToScene(event.pos()))

class SimplePicker(QDialog):

def __init__(self, data, parent=None):
super().__init__(parent=parent)

# Get a grayscale image
bdata = ((data - data.min()) / (data.max() - data.min()) * 255).astype(np.uint8)
wid, hgt = bdata.shape
img = QImage(bdata.T.copy(), wid, hgt, wid,
QImage.Format_Indexed8)

# Construct a scene with pixmap
self.scene = QGraphicsScene(0, 0, wid, hgt, self)
self.scene.setSceneRect(0, 0, wid, hgt)
self.px = self.scene.addPixmap(QPixmap.fromImage(img))

# Construct the view and connect mouse clicks
self.view = MyView(self.scene, self)
self.view.mousedown.connect(self.mouse_click)

# End button
self.doneb = QPushButton('Done', self)
self.doneb.clicked.connect(self.accept)

# Layout
layout = QVBoxLayout(self)
layout.addWidget(self.view)
layout.addWidget(self.doneb)

@pyqtSlot(QPointF)
def mouse_click(self, xy):
print((xy.x(), xy.y()))


if __name__ == "__main__":

# Fake data
x, y = np.mgrid[0:4*np.pi:150j, 0:4*np.pi:200j]
z = np.sin(x) * np.sin(y)

qapp = QApplication.instance()
if qapp is None:
qapp = QApplication(['python'])

pick = SimplePicker(z)

print("Size is (150, 200)")
print("Putting in (50, 125) - This point should return (50.0, 75.0)")
p0 = QPoint(50, 125)
print("Before show():", pick.view.mapToScene(p0))

pick.show()
print("After show() :", pick.view.mapToScene(p0))

qapp.exec_()

此示例是在 Windows 上的 PyQt5 中,但在 Linux 上的 PyQt4 中做同样的事情。

最佳答案

深入了解 C++ Qt 源代码后,这是 QPoint 的 mapToScene 的 Qt 定义:

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->horizo​​ntalScroll(); 和垂直滚动。 QGraphicsView 总是包含滚动条,即使它们总是关闭或不显示。在显示小部件之前观察到的偏移量来自初始化时水平和垂直滚动条的值,当显示小部件和计算布局时,必须修改这些值以匹配 View /视口(viewport)。为了使 mapToScene 正常运行,必须设置滚动条以匹配场景/ View 。

如果我在示例中将以下行放在对 mapToScene 的调用之前,那么我将获得适当的转换结果,而无需显示小部件。

pick.view.horizontalScrollBar().setRange(0, 150)
pick.view.verticalScrollBar().setRange(-200, 0)
pick.view.horizontalScrollBar().setValue(0)
pick.view.verticalScrollBar().setValue(-200)

要更普遍地执行此操作,您可以从 View 中提取一些相关的转换。

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

这是一个 hack-ish 和丑陋的解决方案,所以虽然它确实有效,但可能有更优雅的方式来处理这个问题。

关于python - mapToScene 需要显示正确转换的 View 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43507616/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com