I'm trying to load and query a JS map widget from inside a PyQt5 application. I'm able to use the method:
PyQt5.QtWebEngineWidgets.QWebEngineView().page().runJavaScript()
to execute JS function from the webpage loaded in a QWebEngineView()
but I'm having troubles in understanding how to store back to python a value which is returned by a JS function.
A complete example is available here:
The following PyQt5 code load an html page (pyqtwebtest.html
) with a leaflet.js
map widget inside a PyQt4 mainwindow and add a button to execute a JS code with the aim to store the returned value inside a python variable ...
#!/usr/local/bin/python36
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.form_widget = FormWidget(self)
_widget = QWidget()
_layout = QVBoxLayout(_widget)
_layout.addWidget(self.form_widget)
self.setCentralWidget(_widget)
class FormWidget(QWidget):
def __init__(self, parent):
super(FormWidget, self).__init__(parent)
self.__controls()
self.__layout()
def __controls(self):
self.browser = QWebEngineView()
self.browser.load(QUrl('file:///Users/epi/pyqtwebtest.html'))
def __layout(self):
self.vbox = QVBoxLayout()
self.hBox = QVBoxLayout()
self.getboundsbutton = QPushButton()
self.hBox.addWidget(self.browser)
self.hBox.addWidget(self.getboundsbutton)
self.vbox.addLayout(self.hBox)
self.setLayout(self.vbox)
self.getboundsbutton.clicked.connect(self.getBounds)
def getBounds(self):
self.bounds = self.browser.page().runJavaScript("[map.getBounds().getSouthWest().lat, map.getBounds().getSouthWest().lng, map.getBounds().getNorthEast().lat, map.getBounds().getNorthEast().lng]")
print(self.bounds)
# this is where I get stuck .. the result is None
# the same js code in the html file prints the bounds values
# that I want to store on the python side of the app
def main():
app = QApplication(sys.argv)
win = MainWindow()
win.show()
app.exec_()
if __name__ == '__main__':
sys.exit(main())
which load the following html page:
<!DOCTYPE html>
<html>
<head>
<title>PyQtLeaflet</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<style>
#map {
width: 600px;
height: 400px;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
var mbAttr = 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
mbUrl = 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpandmbXliNDBjZWd2M2x6bDk3c2ZtOTkifQ._QA7i5Mpkd_m30IGElHziw';
var grayscale = L.tileLayer(mbUrl, {id: 'mapbox.light', attribution: mbAttr}),
streets = L.tileLayer(mbUrl, {id: 'mapbox.streets', attribution: mbAttr});
var map = L.map('map', {
center: [10, 10],
zoom: 10,
layers: [grayscale]
});
var baseLayers = {
"Grayscale": grayscale,
"Streets": streets
};
L.control.layers(baseLayers).addTo(map);
// this is the "bounds" variable which I am trying to get from pyqt
bounds = [map.getBounds().getSouthWest().lat, map.getBounds().getSouthWest().lng, map.getBounds().getNorthEast().lat, map.getBounds().getNorthEast().lng]
console.log(bounds)
</script>
</body>
</html>
I understand that this question may be considered a duplicate but I had difficulties in finding the exact same methods for a recent version of pyqt5 (>=5.7)
runJavaScript
in QtWebEngine works asynchronously, so it never returns a value - instead, you pass a callback (i.e. a Python function) to it which gets called with the javascript value. For your example, you could simply pass print
as second argument.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With