我有一个包含多个自定义QGraphicsItems的QGraphicsScene。每个项目都包含一个QGraphicsProxyWidget,它本身包含业务逻辑所需的任何小部件。代理有一个Qt :: Window标志,因此它有一个标题栏来移动它。这一切都运行良好,除非在缩放视图时移动代理窗口小部件。
用户可以在谷歌地图中移动场景,即缩小然后稍微放大一点。这是通过调用QGraphicsView :: scale完成的。无论缩放值如何,项都应始终可见,因此它们设置了QGraphicsItem :: ItemIgnoresTransformations标志。
在缩放视图时移动proxyWidget时会发生的情况是,在第一次移动事件中,窗口小部件会在正确拖动之前跳转到某个位置。
我在Qt5.7.1中遇到过这个问题,并且可以使用PyQt5重现它,因为它更容易重现和破解,请参阅下面的代码片段。
重现的步骤:
段:
import sys
import PyQt5
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsProxyWidget, QGraphicsWidget, QGraphicsObject
global view
global scaleLabel
def scaleScene(event):
delta = 1.0015**event.angleDelta().y()
view.scale(delta, delta)
scaleLabel.setPlainText("scale: %.2f"%view.transform().m11())
view.update()
if __name__ == '__main__':
app = QApplication(sys.argv)
# create main widget
w = QWidget()
w.resize(800, 600)
layout = QVBoxLayout()
w.setLayout(layout)
w.setWindowTitle('Example')
w.show()
# rescale view on mouse wheel, notice how when view.transform().m11() is not 1,
# dragging the subwindow is not smooth on the first mouse move event
w.wheelEvent = scaleScene
# create scene and view
scene = QGraphicsScene()
scaleLabel = scene.addText("scale: 1")
view = QGraphicsView(scene)
layout.addWidget(view)
view.show();
# create item in which the proxy lives
item = QGraphicsWidget()
scene.addItem(item)
item.setFlag(PyQt5.QtWidgets.QGraphicsItem.ItemIgnoresTransformations)
item.setAcceptHoverEvents(True)
# create proxy with window and dummy content
proxy = QGraphicsProxyWidget(item, Qt.Window)
button = QPushButton('dummy')
proxy.setWidget(button)
# start app
sys.exit(app.exec_())
跳跃距离为:
我正在寻找
由于
答案 0 :(得分:0)
大约2年后,我再次回到了这个问题,终于找到了解决方案。或者说是一种解决方法,但至少是一个简单的解决方法。事实证明,我可以很轻松地避免一开始就遇到本地/场景/忽略的转换问题。
我没有直接将QGraphicsProxyWidget附加到QGraphicsWidget,而是将QWidget显式设置为代理目标,而是直接从QGraphicsScene获取代理,让它在包装器上设置窗口标志,并在代理上设置ItemIgnoresTransformations标志。然后(这是解决方法),我在代理上安装了一个事件过滤器,拦截GraphicsSceneMouseMove事件,在该事件中我将代理位置强制为currentPos + mouseDelta(均在场景坐标中)。
这是上面的代码示例,并用该解决方案进行了修补:
import sys
import PyQt5
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import *
global view
global scaleLabel
def scaleScene(event):
delta = 1.0015**event.angleDelta().y()
view.scale(delta, delta)
scaleLabel.setPlainText("scale: %.2f"%view.transform().m11())
view.update()
class ItemFilter(PyQt5.QtWidgets.QGraphicsItem):
def __init__(self, target):
super(ItemFilter, self).__init__()
self.target = target
def boundingRect(self):
return self.target.boundingRect()
def paint(self, *args, **kwargs):
pass
def sceneEventFilter(self, watched, event):
if watched != self.target:
return False
if event.type() == PyQt5.QtCore.QEvent.GraphicsSceneMouseMove:
self.target.setPos(self.target.pos()+event.scenePos()-event.lastScenePos())
event.setAccepted(True)
return True
return super(ItemFilter, self).sceneEventFilter(watched, event)
if __name__ == '__main__':
app = QApplication(sys.argv)
# create main widget
w = QWidget()
w.resize(800, 600)
layout = QVBoxLayout()
w.setLayout(layout)
w.setWindowTitle('Example')
w.show()
# rescale view on mouse wheel, notice how when view.transform().m11() is not 1,
# dragging the subwindow is not smooth on the first mouse move event
w.wheelEvent = scaleScene
# create scene and view
scene = QGraphicsScene()
scaleLabel = scene.addText("scale: 1")
view = QGraphicsView(scene)
layout.addWidget(view)
view.show();
button = QPushButton('dummy')
proxy = scene.addWidget(button, Qt.Window)
proxy.setFlag(PyQt5.QtWidgets.QGraphicsItem.ItemIgnoresTransformations)
itemFilter = ItemFilter(proxy)
scene.addItem(itemFilter)
proxy.installSceneEventFilter(itemFilter)
# start app
sys.exit(app.exec_())
希望这可以帮助那些陷入与我同样死胡同的人:)