gpt4 book ai didi

qt5 - 更改 QGraphicsView 比例后使用 ItemIgnoresTransformations 移动 QGraphicsProxyWidget

转载 作者:行者123 更新时间:2023-12-02 04:36:30 24 4
gpt4 key购买 nike

我有一个包含多个自定义 QGraphicsItem 的 QGraphicsScene。每个项目都包含一个 QGraphicsProxyWidget,它本身包含业务逻辑所需的任何小部件。代理有一个应用到它的 Qt::Window 标志,因此它有一个标题栏来移动它。这一切都运行良好,除了在缩放 View 时移动代理小部件时。

用户可以像谷歌地图那样在场景中四处移动,即通过缩小然后再放大到更远的地方。这是通过调用 QGraphicsView::scale 完成的。无论缩放值如何,项目都应始终可见,因此它们设置了 QGraphicsItem::ItemIgnoresTransformations 标志。

在缩放 View 时移动 proxyWidget 时发生的情况是,在第一次移动事件中,小部件将跳转到某个位置,然后才能正确拖动。

我在 Qt5.7.1 上遇到了这个问题,可以用 PyQt5 重现它,因为它更容易重现和修改,请看下面的代码片段。

重现步骤:

  1. 四处移动小部件,注意没有异常
  2. 使用鼠标滚轮放大或缩小。绝对规模越高,对问题的影响就越大。
  3. 单击小部件,注意它如何在第一次移动鼠标时跳跃。

片段:

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

跳跃距离为:

  • 与 View 的缩放比例以及鼠标与场景原点的距离成比例
  • 从场景位置 (0,0) 到鼠标位置(我认为)
  • 可能是由于代理小部件未正确报告鼠标按下/移动引起的。在查看 qgraphicsproxywidget.cpp ( sample source ) 中的 QGraphicsProxyWidgetPrivate::mapToReceiver 后,我得到了这个诊断的提示,它似乎没有考虑场景缩放。

我正在寻找任何一个

  • 确认这是 Qt 的问题并且我没有错误配置代理。
  • 关于如何修复代理给它的子部件的鼠标位置的解释(在安装 eventFilter 之后)
  • 任何其他解决方法

谢谢

最佳答案

将近 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_())

希望这可以帮助那些和我一样陷入死胡同的人:)

关于qt5 - 更改 QGraphicsView 比例后使用 ItemIgnoresTransformations 移动 QGraphicsProxyWidget,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42182399/

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