[英]GraphicsView Scene postEvent focusProxy does not pass events from event filter to QWebEngineView Widget
我目前正在学习如何在 PyQt5 中编写一个 GUI,使用户能够在QGrapchisView Scene
中绘制线条和矩形,并设置一个包含叶 map 作为背景的QWebEngineView
Widget。
问题:为了同步QGrapchisView
场景和 folium map 平移和缩放,我使用了将GraphicsScene
事件传递给QWebEngineView
Widget 的事件过滤器。
QEvent.GraphicsSceneWheel
事件按预期传递,但QEvent.GraphicsSceneMouseRelease
、 QEvent.GraphicsSceneMousePress
和QEvent.GraphicsSceneMouseMove
未传递给QWebEngineView
小部件。
预期行为:选定的 GraphicsScene 事件被传递给 QWebEngineView 小部件,它可以同步两个小部件的平移和缩放。
到目前为止我已经尝试过:
import folium
import sys
from PyQt5 import QtGui, QtCore, QtWidgets, QtWebEngineWidgets
import io
class eventFilterClass(QtCore.QObject):
def __init__(self, sender, receiver, gv):
super(eventFilterClass, self).__init__()
self.gv = gv
self.m_sender = sender
self.m_receiver = receiver
self.m_sender.installEventFilter(self)
def eventFilter(self, obj, event):
if self.m_sender is obj:
if event.type() == QtCore.QEvent.GraphicsSceneMousePress:
if event.button() == QtCore.Qt.MiddleButton:
new_event = QtGui.QMouseEvent(int(2), self.gv.mapFromScene(event.scenePos()),
self.gv.mapFromScene(event.scenePos()), event.screenPos(), event.button(),
event.buttons(), event.modifiers(), event.source())
QtCore.QCoreApplication.postEvent(self.m_receiver.focusProxy(), new_event)
return True
elif event.type() == QtCore.QEvent.GraphicsSceneMouseMove:
if event.buttons() == QtCore.Qt.NoButton:
new_event = QtGui.QMouseEvent(int(5), self.gv.mapFromScene(event.scenePos()),self.gv.mapFromScene(event.scenePos()), event.screenPos(), event.button(), event.buttons(), event.modifiers(), event.source())
QtCore.QCoreApplication.postEvent(self.m_receiver.focusProxy(), new_event)
return True
elif event.type() == QtCore.QEvent.GraphicsSceneMouseRelease:
print('Release!')
if event.button() == QtCore.Qt.MiddleButton:
new_event = QtGui.QMouseEvent(int(3), self.gv.mapFromScene(event.scenePos()),
self.gv.mapFromScene(event.scenePos()), event.screenPos(), event.button(),
event.buttons(), event.modifiers(), event.source())
QtCore.QCoreApplication.postEvent(self.m_receiver.focusProxy(), new_event)
elif event.type() == QtCore.QEvent.GraphicsSceneWheel:
new_event = QtGui.QWheelEvent(self.gv.mapFromScene(event.scenePos()), event.screenPos(), QtCore.QPoint(), QtCore.QPoint(0, event.delta()),event.buttons(), event.modifiers(), int(0), False, int(0))
QtCore.QCoreApplication.postEvent(self.m_receiver.focusProxy(), new_event)
return True
return False
class GraphicsView(QtWidgets.QGraphicsView):
def __init__(self, parent, scene=None):
super(GraphicsView, self).__init__(scene, parent)
"VARIABLES INICIALES"
self.pos_init_class = None
self.scale_factor = 1.25
"ACTIVAR TRACKING DE POSICION DE MOUSE"
self.setMouseTracking(True)
"REMOVER BARRAS DE SCROLL"
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
"ASIGNAR ANCLA PARA HACER ZOOM SOBRE EL MISMO PUNTO"
self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
def wheelEvent(self, event):
if event.angleDelta().y() > 0:
self.scale(self.scale_factor, self.scale_factor)
else:
self.scale(1 / self.scale_factor, 1 / self.scale_factor)
super(GraphicsView, self).wheelEvent(event)
def mousePressEvent(self, event):
pos = self.mapToScene(event.pos())
"PAN"
if event.button() == QtCore.Qt.MiddleButton:
self.pos_init_class = pos
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.ClosedHandCursor)
super(GraphicsView, self).mousePressEvent(event)
return
super(GraphicsView, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
pos = self.mapToScene(event.pos())
"PAN"
if self.pos_init_class:
delta = self.pos_init_class - self.mapToScene(event.pos())
r = self.mapToScene(self.viewport().rect()).boundingRect()
self.setSceneRect(r.translated(delta))
return
super(GraphicsView, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
"PAN"
if self.pos_init_class and event.button() == QtCore.Qt.MiddleButton:
self.pos_init_class = None
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.ArrowCursor)
super(GraphicsView, self).mouseReleaseEvent(event)
class Ui_MainWindow(object):
def __init__(self):
super(Ui_MainWindow, self).__init__()
def zoom_ext(self):
"Zoom extent"
x_range, y_range, h_range, w_range = self.graphicsView.scene().itemsBoundingRect().getRect()
rect_scene = QtCore.QRectF(x_range, y_range, h_range, w_range)
self.graphicsView.setSceneRect(rect_scene)
unity = self.graphicsView.transform().mapRect(QtCore.QRectF(0, 0, 1, 1))
self.graphicsView.scale(1 / unity.width(), 1 / unity.height())
viewrect = self.graphicsView.viewport().rect()
scenerect = self.graphicsView.transform().mapRect(rect_scene)
factor = min(viewrect.width() / scenerect.width(), viewrect.height() / scenerect.height())
self.graphicsView.scale(factor, factor)
def draw_lines(self):
cancha = QtGui.QPolygonF([
QtCore.QPointF(721383.8266, -9678885.4514),
QtCore.QPointF(721404.5488, -9678961.6564),
QtCore.QPointF(721453.4389, -9678948.7816),
QtCore.QPointF(721433.20288, -9678871.92070)])
self.graphicsView.scene().addPolygon(cancha, QtGui.QPen(QtCore.Qt.red, 2.5, QtCore.Qt.SolidLine))
caseta = QtGui.QPolygonF([
QtCore.QPointF(721455.8594, -9678925.4517),
QtCore.QPointF(721492.5411, -9678915.2403),
QtCore.QPointF(721498.3404, -9678937.9702),
QtCore.QPointF(721461.7904, -9678947.5050)])
self.graphicsView.scene().addPolygon(caseta, QtGui.QPen(QtCore.Qt.red, 2.5, QtCore.Qt.SolidLine))
def setupUi(self, MainWindow):
"CENTRAL WIDGET"
self.centralwidget = QtWidgets.QWidget(MainWindow)
MainWindow.setCentralWidget(self.centralwidget)
MainWindow.resize(1000, 1000)
"WEB MAP"
self.w = QtWebEngineWidgets.QWebEngineView(self.centralwidget)
self.w.setGeometry(QtCore.QRect(0, 0, 1000, 1000))
"QGRAPCHISVIEW SCENE"
self.graphicsView = GraphicsView(parent=self.centralwidget)
self.scene = QtWidgets.QGraphicsScene(parent=self.graphicsView)
self.graphicsView.setScene(self.scene)
self.graphicsView.setGeometry(QtCore.QRect(0, 0, 1000, 1000))
self.graphicsView.setStyleSheet("background:transparent;")
"Draw LINES"
self.draw_lines()
"ZOOM EXT"
self.zoom_ext()
"AGREAGR MAPA"
self.m = folium.Map(tiles='http://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}', attr='Google Satellite', zoomSnap=0.0, wheelDebounceTime=-1,
wheelPxPerZoomLevel=105, prefer_canvas=True, control_scale=True, max_zoom=100000,
zoomControl=False)
sw, ne = (-2.903683906544795, -79.00835706455769), (-2.9026234455284583, -79.00729860799157)
self.m.fit_bounds([sw, ne], padding=(0, 0))
data = io.BytesIO()
self.m.save(data, close_file=False)
self.w.setHtml(data.getvalue().decode())
"APLICAR FILTER"
self.efc = eventFilterClass(sender=self.graphicsView.scene(), receiver=self.w, gv=self.graphicsView)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
问题:
有没有其他方法可以做到这一点?
看来 OP 试图通过不必要地采用自定义参数来创建事件。 在我的解决方案中,我建议只复制参数:
import io
import sys
from PyQt5 import QtGui, QtCore, QtWidgets, QtWebEngineWidgets
import folium
class ReplyEvents(QtCore.QObject):
def __init__(self, sender, receiver, parent=None):
super().__init__(parent)
self._sender = sender
self._receiver = receiver
self._sender.installEventFilter(self)
def eventFilter(self, obj, event):
if obj is self._sender:
new_event = None
if event.type() in (
QtCore.QEvent.MouseButtonPress,
QtCore.QEvent.MouseButtonRelease,
QtCore.QEvent.MouseButtonDblClick,
QtCore.QEvent.MouseMove,
):
new_event = QtGui.QMouseEvent(
event.type(),
event.pos(),
event.button(),
event.buttons(),
event.modifiers(),
)
elif event.type() == QtCore.QEvent.Wheel:
new_event = QtGui.QWheelEvent(
event.pos(),
event.globalPosition(),
event.pixelDelta(),
event.angleDelta(),
event.buttons(),
event.modifiers(),
event.phase(),
event.inverted(),
)
if new_event:
QtCore.QCoreApplication.postEvent(self._receiver, new_event)
return super().eventFilter(obj, event)
class GraphicsView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
self.scale_factor = 1.25
self.pos_init_class = QtCore.QPointF()
scene = QtWidgets.QGraphicsScene(self)
self.setScene(scene)
self.setStyleSheet("background:transparent;")
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
self.setMouseTracking(True)
def wheelEvent(self, event):
if event.angleDelta().y() > 0:
self.scale(self.scale_factor, self.scale_factor)
else:
self.scale(1 / self.scale_factor, 1 / self.scale_factor)
super().wheelEvent(event)
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.MiddleButton:
self.pos_init_class = self.mapToScene(event.pos())
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.ClosedHandCursor)
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if not self.pos_init_class.isNull():
delta = self.pos_init_class - self.mapToScene(event.pos())
r = self.mapToScene(self.viewport().rect()).boundingRect()
self.setSceneRect(r.translated(delta))
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
if not self.pos_init_class.isNull() and event.button() == QtCore.Qt.MiddleButton:
self.pos_init_class = QtCore.QPointF()
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.ArrowCursor)
super().mouseReleaseEvent(event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(1000, 1000)
self.web_view = QtWebEngineWidgets.QWebEngineView(self)
self.graphics_view = GraphicsView(self)
geometry = QtCore.QRect(0, 0, 1000, 1000)
self.web_view.setGeometry(geometry)
self.graphics_view.setGeometry(geometry)
self.draw_lines()
self.zoom_ext()
m = folium.Map(
tiles="http://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}",
attr="Google Satellite",
zoomSnap=0.0,
wheelDebounceTime=-1,
wheelPxPerZoomLevel=105,
prefer_canvas=True,
control_scale=True,
max_zoom=100000,
zoomControl=False,
)
sw, ne = (
(-2.903683906544795, -79.00835706455769),
(-2.9026234455284583, -79.00729860799157),
)
m.fit_bounds([sw, ne], padding=(0, 0))
data = io.BytesIO()
m.save(data, close_file=False)
self.web_view.setHtml(data.getvalue().decode())
r = ReplyEvents(self.graphics_view.viewport(), self.web_view.focusProxy(), self)
def draw_lines(self):
cancha = QtGui.QPolygonF(
[
QtCore.QPointF(721383.8266, -9678885.4514),
QtCore.QPointF(721404.5488, -9678961.6564),
QtCore.QPointF(721453.4389, -9678948.7816),
QtCore.QPointF(721433.20288, -9678871.92070),
]
)
self.graphics_view.scene().addPolygon(
cancha, QtGui.QPen(QtCore.Qt.red, 2.5, QtCore.Qt.SolidLine)
)
caseta = QtGui.QPolygonF(
[
QtCore.QPointF(721455.8594, -9678925.4517),
QtCore.QPointF(721492.5411, -9678915.2403),
QtCore.QPointF(721498.3404, -9678937.9702),
QtCore.QPointF(721461.7904, -9678947.5050),
]
)
self.graphics_view.scene().addPolygon(
caseta, QtGui.QPen(QtCore.Qt.red, 2.5, QtCore.Qt.SolidLine)
)
def zoom_ext(self):
"Zoom extent"
x_range, y_range, h_range, w_range = (
self.graphics_view.scene().itemsBoundingRect().getRect()
)
rect_scene = QtCore.QRectF(x_range, y_range, h_range, w_range)
self.graphics_view.setSceneRect(rect_scene)
unity = self.graphics_view.transform().mapRect(QtCore.QRectF(0, 0, 1, 1))
self.graphics_view.scale(1 / unity.width(), 1 / unity.height())
viewrect = self.graphics_view.viewport().rect()
scenerect = self.graphics_view.transform().mapRect(rect_scene)
factor = min(
viewrect.width() / scenerect.width(), viewrect.height() / scenerect.height()
)
self.graphics_view.scale(factor, factor)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.