Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return value from javascript to pyqt5

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 &copy; <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)

like image 416
epifanio Avatar asked Mar 10 '23 02:03

epifanio


1 Answers

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.

like image 172
The Compiler Avatar answered Mar 20 '23 12:03

The Compiler