Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
411 views
in Technique[技术] by (71.8m points)

python - How to open download file dialog with QWebEngineView?

I'm building a pyqt5 desktop interface where I'm using QWebEngineView to show a html file where I show a Leaflet map. This is working fine. The next step is to export all features the user added to the map. When I click on "Export Features" on the map nothing happen, but when I open the same html file on my Chromium web browser, the "Export feature" opens the download dialog fine.

PyQt5 script:

self.MainWindow.webMapViewer = QtWebEngineWidgets.QWebEngineView()
self.MainWindow.webPageLayout.addWidget(self.MainWindow.webMapViewer)
self.html_path = os.path.split(os.path.abspath(__file__))[0] + r'/html/test.html'
self.MainWindow.webMapViewer.load(QtCore.QUrl().fromLocalFile(self.html_path))

HTML:

<!DOCTYPE html>
        <html lang="en">
          <head>
            <meta charset="utf-8">
            <meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no' />
            <title>FazMaraneyRGB_transparent_mosaic_group1</title>

            <!-- Leaflet -->
            <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.5/leaflet.css" />
            <script src="http://cdn.leafletjs.com/leaflet-0.7.5/leaflet.js"></script>

            <!-- Leaflet.draw -->
            <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.draw.css" />
            <script src="https://unpkg.com/[email protected]/dist/leaflet.draw.js"></script>

            <!-- Leaflet Ajax -->
            <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-ajax/2.1.0/leaflet.ajax.min.js"></script>

            <!-- Leaflet Measument -->
            <link rel="stylesheet" href="http://ljagis.github.io/leaflet-measure/leaflet-measure.css" />
            <script src="http://ljagis.github.io/leaflet-measure/leaflet-measure.min.js"></script>


            <style>
                body { margin:0; padding:0; }
                body, table, tr, td, th, div, h1, h2, input { font-family: "Calibri", "Trebuchet MS", "Ubuntu", Serif; font-size: 11pt; }
                #map { position:absolute; top:0; bottom:0; width:100%; } /* full size */
                .ctl {
                    padding: 2px 10px 2px 10px;
                    background: white;
                    background: rgba(255,255,255,0.9);
                    box-shadow: 0 0 15px rgba(0,0,0,0.2);
                    border-radius: 5px;
                    text-align: right;
                }
                .title {
                    font-size: 18pt;
                    font-weight: bold;
                }
                .src {
                    font-size: 10pt;
                }
                #delete, #export {
                    position: absolute;
                    top:100px;
                    right:10px;
                    z-index:100;
                    background:white;
                    color:black;
                    padding:6px;
                    border-radius:4px;
                    font-family: 'Helvetica Neue';
                    cursor: pointer;
                    font-size:12px;
                    text-decoration:none;
                }
                #export {
                    top:130px;
                }
            </style>

        </head>
        <body>

        <div id='map'></div>
        <div id='delete'>Delete Features</div>
        <a href='#' id='export'>Export Features</a>

        <script>
        /* **** Leaflet **** */

        // Base layers
        //  .. OpenStreetMap
        var osm = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'});

        //  .. White background
        var white = L.tileLayer("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEAAQMAAABmvDolAAAAA1BMVEX///+nxBvIAAAAH0lEQVQYGe3BAQ0AAADCIPunfg43YAAAAAAAAAAA5wIhAAAB9aK9BAAAAABJRU5ErkJggg==");

        // Overlay layers (TMS)
        var lyr1 = L.tileLayer('./tiles/{z}/{x}/{y}.png', {tms: true, maxZoom: 22, opacity: 0.9, attribution: ""});

        // Map
        var map = L.map('map', {
            measureControl: true,
            center: [-18.3604868606589, -52.694255477616245],
            zoom: 22,
            minZoom: 0,
            maxZoom: 22,
            layers: [osm]
        });

        lyr1.addTo(map);

        //Geojson Layers


        var basemaps = {"OpenStreetMap": osm, "Without background": white}
        var overlaymaps = {"Layer 1": lyr1}

        // Title
        var title = L.control();
        title.onAdd = function(map) {
            this._div = L.DomUtil.create('div', 'ctl title');
            this.update();
            return this._div;
        };
        title.update = function(props) {
            this._div.innerHTML = "FazMaraneyRGB_transparent_mosaic_group1";
        };
        title.addTo(map);

        // Note
        var src = 'Generated by Hawkit';
        var title = L.control({position: 'bottomleft'});
        title.onAdd = function(map) {
            this._div = L.DomUtil.create('div', 'ctl src');
            this.update();
            return this._div;
        };
        title.update = function(props) {
            this._div.innerHTML = src;
        };
        title.addTo(map);

        var featureGroup = L.featureGroup().addTo(map);

        var drawControl = new L.Control.Draw({
            edit: {
                featureGroup: featureGroup
            }
        }).addTo(map);

        map.on('draw:created', function(e) {

            // Each time a feaute is created, it's added to the over arching feature group
            featureGroup.addLayer(e.layer);
        });

        // on click, clear all layers
        document.getElementById('delete').onclick = function(e) {
            featureGroup.clearLayers();
        }

        document.getElementById('export').onclick = function(e) {
            // Extract GeoJson from featureGroup
            var data = featureGroup.toGeoJSON();

            // Stringify the GeoJson
            var convertedData = 'text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(data));

            // Create export
            document.getElementById('export').setAttribute('href', 'data:' + convertedData);
            document.getElementById('export').setAttribute('download','data.geojson');
        }


        // Add base layers
        L.control.layers(basemaps, overlaymaps, {collapsed: true}).addTo(map);

        // Fit to overlay bounds (SW and NE points with (lat, lon))
        map.fitBounds([[-18.36827062251916, -52.6871074784942], [-18.35270287637126, -52.7014028427423]]);

        </script>

        </body>
        </html>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

That popup window is generated by the browser, in the case of QWebEngine we must create it. To start, the signal indicating the download must be detected, and this signal is downloadRequested from the QWebEngineProfile. That signal sends us a QWebEngineDownloadItem object that handles the download, in it we create a dialog window with the help of QFileDialog. For this case we will create a custom QWebEnginePage as shown below:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no' />
    <title>FazMaraneyRGB_transparent_mosaic_group1</title>

    <!-- Leaflet -->
    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.5/leaflet.css" />
    <script src="http://cdn.leafletjs.com/leaflet-0.7.5/leaflet.js"></script>

    <!-- Leaflet.draw -->
    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.draw.css" />
    <script src="https://unpkg.com/[email protected]/dist/leaflet.draw.js"></script>

    <!-- Leaflet Ajax -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-ajax/2.1.0/leaflet.ajax.min.js"></script>

    <!-- Leaflet Measument -->
    <link rel="stylesheet" href="http://ljagis.github.io/leaflet-measure/leaflet-measure.css" />
    <script src="http://ljagis.github.io/leaflet-measure/leaflet-measure.min.js"></script>

    <style>
        body {
            margin: 0;
            padding: 0;
        }
        
        body,
        table,
        tr,
        td,
        th,
        div,
        h1,
        h2,
        input {
            font-family: "Calibri", "Trebuchet MS", "Ubuntu", Serif;
            font-size: 11pt;
        }
        
        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }
        /* full size */
        
        .ctl {
            padding: 2px 10px 2px 10px;
            background: white;
            background: rgba(255, 255, 255, 0.9);
            box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
            border-radius: 5px;
            text-align: right;
        }
        
        .title {
            font-size: 18pt;
            font-weight: bold;
        }
        
        .src {
            font-size: 10pt;
        }
        
        #delete,
        #export {
            position: absolute;
            top: 100px;
            right: 10px;
            z-index: 100;
            background: white;
            color: black;
            padding: 6px;
            border-radius: 4px;
            font-family: 'Helvetica Neue';
            cursor: pointer;
            font-size: 12px;
            text-decoration: none;
        }
        
        #export {
            top: 130px;
        }
    </style>

</head>

<body>

    <div id='map'></div>
    <div id='delete'>Delete Features</div>
    <a href='#' id='export'>Export Features</a>

    <script>
        /* **** Leaflet **** */

        // Base layers
        //  .. OpenStreetMap
        var osm = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
            attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        });

        //  .. White background
        var white = L.tileLayer("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEAAQMAAABmvDolAAAAA1BMVEX///+nxBvIAAAAH0lEQVQYGe3BAQ0AAADCIPunfg43YAAAAAAAAAAA5wIhAAAB9aK9BAAAAABJRU5ErkJggg==");

        // Overlay layers (TMS)
        var lyr1 = L.tileLayer('./tiles/{z}/{x}/{y}.png', {
            tms: true,
            maxZoom: 22,
            opacity: 0.9,
            attribution: ""
        });

        // Map
        var map = L.map('map', {
            measureControl: true,
            center: [-18.3604868606589, -52.694255477616245],
            zoom: 22,
            minZoom: 0,
            maxZoom: 22,
            layers: [osm]
        });

        lyr1.addTo(map);

        //Geojson Layers

        var basemaps = {
            "OpenStreetMap": osm,
            "Without background": white
        }
        var overlaymaps = {
            "Layer 1": lyr1
        }

        // Title
        var title = L.control();
        title.onAdd = function(map) {
            this._div = L.DomUtil.create('div', 'ctl title');
            this.update();
            return this._div;
        };
        title.update = function(props) {
            this._div.innerHTML = "FazMaraneyRGB_transparent_mosaic_group1";
        };
        title.addTo(map);

        // Note
        var src = 'Generated by Hawkit';
        var title = L.control({
            position: 'bottomleft'
        });
        title.onAdd = function(map) {
            this._div = L.DomUtil.create('div', 'ctl src');
            this.update();
            return this._div;
        };
        title.update = function(props) {
            this._div.innerHTML = src;
        };
        title.addTo(map);

        var featureGroup = L.featureGroup().addTo(map);

        var drawControl = new L.Control.Draw({
            edit: {
                featureGroup: featureGroup
            }
        }).addTo(map);

        map.on('draw:created', function(e) {

            // Each time a feaute is created, it's added to the over arching feature group
            featureGroup.addLayer(e.layer);
        });

        // on click, clear all layers
        document.getElementById('delete').onclick = function(e) {
            featureGroup.clearLayers();
        }

        document.getElementById('export').onclick = function(e) {
            // Extract GeoJson from featureGroup
            var data = featureGroup.toGeoJSON();

            // Stringify the GeoJson
            var convertedData = 'text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(data));

            // Create export
            document.getElementById('export').setAttribute('href', 'data:' + convertedData);
            document.getElementById('export').setAttribute('download', 'data.geojson');
        }

        // Add base layers
        L.control.layers(basemaps, overlaymaps, {
            collapsed: true
        }).addTo(map);

        // Fit to overlay bounds (SW and NE points with (lat, lon))
        map.fitBounds([
            [-18.36827062251916, -52.6871074784942],
            [-18.35270287637126, -52.7014028427423]
        ]);
    </script>

</body>

</html>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...