简体   繁体   English

如何使用QWebEngineView打开下载文件对话框?

[英]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. 我正在构建pyqt5桌面界面,在其中使用QWebEngineView来显示html文件,并在其中显示Leaflet映射。 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. 当我单击地图上的“导出功能”时,什么也没有发生,但是当我在Chromium Web浏览器中打开相同的html文件时,“导出功能”可以很好地打开下载对话框。

PyQt5 script: PyQt5脚本:

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: 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/leaflet-draw@0.4.1/dist/leaflet.draw.css" />
            <script src="https://unpkg.com/leaflet-draw@0.4.1/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>

That popup window is generated by the browser, in the case of QWebEngine we must create it. 该弹出窗口是由浏览器生成的,对于QWebEngine我们必须创建它。 To start, the signal indicating the download must be detected, and this signal is downloadRequested from the QWebEngineProfile . 首先,必须检测到指示下载的信号,然后从QWebEngineProfile downloadRequested该信号。 That signal sends us a QWebEngineDownloadItem object that handles the download, in it we create a dialog window with the help of QFileDialog . 该信号发送给我们一个处理下载的QWebEngineDownloadItem对象,在其中我们借助QFileDialog创建一个对话框窗口。 For this case we will create a custom QWebEnginePage as shown below: 对于这种情况,我们将创建一个自定义QWebEnginePage,如下所示:

index.html 的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/leaflet-draw@0.4.1/dist/leaflet.draw.css" /> <script src="https://unpkg.com/leaflet-draw@0.4.1/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> 

main.py main.py

from PyQt5 import QtWebEngineWidgets, QtWidgets, QtCore

class WebEnginePage(QtWebEngineWidgets.QWebEnginePage):
    def __init__(self, *args, **kwargs):
        QtWebEngineWidgets.QWebEnginePage.__init__(self, *args, **kwargs)
        self.profile().downloadRequested.connect(self.on_downloadRequested)

    @QtCore.pyqtSlot(QtWebEngineWidgets.QWebEngineDownloadItem)
    def on_downloadRequested(self, download):
        old_path = download.path()
        suffix = QtCore.QFileInfo(old_path).suffix()
        path, _ = QtWidgets.QFileDialog.getSaveFileName(self.view(), "Save File", old_path, "*."+suffix)
        if path:
            download.setPath(path)
            download.accept()


if __name__ == '__main__':
    import sys

    sys.argv.append("--remote-debugging-port=8000")
    sys.argv.append("--disable-web-security")

    app = QtWidgets.QApplication(sys.argv)
    view = QtWebEngineWidgets.QWebEngineView()
    page = WebEnginePage(view)
    view.setPage(page)
    path = QtCore.QDir.current().filePath("index.html")
    view.load(QtCore.QUrl.fromLocalFile(path))
    view.show()
    sys.exit(app.exec_())

In your case: 在您的情况下:

self.MainWindow.webMapViewer = QtWebEngineWidgets.QWebEngineView()
self.MainWindow.webPageLayout.addWidget(self.MainWindow.webMapViewer)
page = WebEnginePage(self.MainWindow.webMapViewer) # create page
self.MainWindow.webMapViewer.setPage(page) # set page
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))

Plus: 加:

If you want to set a defined route use the following: 如果要设置定义的路由,请使用以下命令:

@QtCore.pyqtSlot(QtWebEngineWidgets.QWebEngineDownloadItem)
def on_downloadRequested(self, download):
    directory = "/path/of/directory"
    filename = QtCore.QFileInfo(download.path()).fileName()
    download.setPath(QtCore.QDir(directory).filePath(filename))
    download.accept()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM