如何在pyqt5中创建小部件以显示Google Map [英] How to create widget in pyqt5 to show google map

查看:230
本文介绍了如何在pyqt5中创建小部件以显示Google Map的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何从用户获取经度和纬度,并在pyqt5小部件中在地图上显示此位置?

How do I get latitude and longitude from user and show this location on map in pyqt5 widget?

我的操作系统是Windows,我发现了此链接:

My OS is Windows, and I found out this link:

https://github.com/eyllanesc/qMap

但是在运行时,发生了此错误:

But when run, this error occurred:

ModuleNotFoundError: No module named 'PyQt5.QtWebKit'

总而言之,如何在pyqt5中创建小部件以显示Google地图?

In summary, how to create widget in pyqt5 to show google map?

推荐答案

QtWebkit自Qt 5.6起已被弃用,并由Qt WebEngine取代,PyQt也是如此,后者会产生错误.另一方面,我的库使用Qt Webkit来实现它,而我还没有时间为PyQt来实现它,但是今天我已经做到了(它尚未经过全面测试).

QtWebkit is deprecated from Qt 5.6 and was replaced by Qt WebEngine, and the same goes for PyQt, which generates the error. On the other hand my library implements it using Qt Webkit and I have not had time to implement it for PyQt but today I have done it (it is not fully tested).

据观察,Google Maps当前需要一个API密钥,您可以通过其他指南.

As an observation, Google Maps currently requires a API KEY that you can obtain by following this guide. Also the class provides to get the position given the place name but you also have to enable it using this other guide.

为您进行快速测试,我将提供一个API KEY,但我会随时将其禁用.

main.py

import json

from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets, QtWebChannel, QtNetwork

HTML = '''
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
    <style type="text/css">
        html {
            height: 100%;
        }
        body {
            height: 100%;
            margin: 0;
            padding: 0
        }
        #map_canvas {
            height: 100%
        }
    </style>
    <script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
    <script async defer
            src="https://maps.googleapis.com/maps/api/js?key=API_KEY"
            type="text/javascript"></script>
    <script type="text/javascript" src="qgmap.js"></script>
</head>
<body onload="initialize()">
<div id="map_canvas" style="width:100%; height:100%"></div>
</body>
</html>
'''

JS = '''
// main var
var map;
var markers = [];
var qtWidget;

// main init function
function initialize() {
    var myOptions = {
        center: {lat: -34.397, lng: 150.644},
        zoom: 8
    };

    map = new google.maps.Map(document.getElementById('map_canvas'),
        myOptions);

    new QWebChannel(qt.webChannelTransport, function (channel) {
        qtWidget = channel.objects.qGoogleMap;
    });

    google.maps.event.addListener(map, 'dragend', function () {
        var center = map.getCenter();
        qtWidget.mapIsMoved(center.lat(), center.lng());
    });
    google.maps.event.addListener(map, 'click', function (ev) {
        qtWidget.mapIsClicked(ev.latLng.lat(), ev.latLng.lng());
    });
    google.maps.event.addListener(map, 'rightclick', function (ev) {
        qtWidget.mapIsRightClicked(ev.latLng.lat(), ev.latLng.lng());
    });
    google.maps.event.addListener(map, 'dblclick', function (ev) {
        qtWidget.mapIsDoubleClicked(ev.latLng.lat(), ev.latLng.lng());
    });
}
// custom functions
function gmap_setCenter(lat, lng) {
    map.setCenter(new google.maps.LatLng(lat, lng));
}
function gmap_getCenter() {
    return [map.getCenter().lat(), map.getCenter().lng()];
}
function gmap_setZoom(zoom) {
    map.setZoom(zoom);
}
function gmap_addMarker(key, latitude, longitude, parameters) {

    if (key in markers) {
        gmap_deleteMarker(key);
    }
    var coords = new google.maps.LatLng(latitude, longitude);
    parameters['map'] = map
    parameters['position'] = coords;
    var marker = new google.maps.Marker(parameters);
    google.maps.event.addListener(marker, 'dragend', function () {
        qtWidget.markerIsMoved(key, marker.position.lat(), marker.position.lng())
    });
    google.maps.event.addListener(marker, 'click', function () {
        qtWidget.markerIsClicked(key, marker.position.lat(), marker.position.lng())
    });
    google.maps.event.addListener(marker, 'dblclick', function () {
        qtWidget.markerIsDoubleClicked(key, marker.position.lat(), marker.position.lng())
    });
    google.maps.event.addListener(marker, 'rightclick', function () {
        qtWidget.markerIsRightClicked(key, marker.position.lat(), marker.position.lng())
    });
    markers[key] = marker;
    return key;
}
function gmap_moveMarker(key, latitude, longitude) {
    var coords = new google.maps.LatLng(latitude, longitude);
    markers[key].setPosition(coords);
}
function gmap_deleteMarker(key) {
    markers[key].setMap(null);
    delete markers[key]
}
function gmap_changeMarker(key, extras) {
    if (!(key in markers)) {
        return
    }
    markers[key].setOptions(extras);
}
'''


class GeoCoder(QtNetwork.QNetworkAccessManager):
    class NotFoundError(Exception):
        pass

    def geocode(self, location, api_key):
        url = QtCore.QUrl("https://maps.googleapis.com/maps/api/geocode/xml")

        query = QtCore.QUrlQuery()
        query.addQueryItem("key", api_key)
        query.addQueryItem("address", location)
        url.setQuery(query)
        request = QtNetwork.QNetworkRequest(url)
        reply = self.get(request)
        loop = QtCore.QEventLoop()
        reply.finished.connect(loop.quit)
        loop.exec_()
        reply.deleteLater()
        self.deleteLater()
        return self._parseResult(reply)

    def _parseResult(self, reply):
        xml = reply.readAll()
        reader = QtCore.QXmlStreamReader(xml)
        while not reader.atEnd():
            reader.readNext()
            if reader.name() != "geometry": continue
            reader.readNextStartElement()
            if reader.name() != "location": continue
            reader.readNextStartElement()
            if reader.name() != "lat": continue
            latitude = float(reader.readElementText())
            reader.readNextStartElement()
            if reader.name() != "lng": continue
            longitude = float(reader.readElementText())
            return latitude, longitude
        raise GeoCoder.NotFoundError


class QGoogleMap(QtWebEngineWidgets.QWebEngineView):
    mapMoved = QtCore.pyqtSignal(float, float)
    mapClicked = QtCore.pyqtSignal(float, float)
    mapRightClicked = QtCore.pyqtSignal(float, float)
    mapDoubleClicked = QtCore.pyqtSignal(float, float)

    markerMoved = QtCore.pyqtSignal(str, float, float)
    markerClicked = QtCore.pyqtSignal(str, float, float)
    markerDoubleClicked = QtCore.pyqtSignal(str, float, float)
    markerRightClicked = QtCore.pyqtSignal(str, float, float)

    def __init__(self, api_key, parent=None):
        super(QGoogleMap, self).__init__(parent)
        self._api_key = api_key
        channel = QtWebChannel.QWebChannel(self)
        self.page().setWebChannel(channel)
        channel.registerObject("qGoogleMap", self)
        self.page().runJavaScript(JS)

        html = HTML.replace("API_KEY", "YOUR_API_KEY_HERE")
        self.setHtml(html)
        self.loadFinished.connect(self.on_loadFinished)
        self.initialized = False

        self._manager = QtNetwork.QNetworkAccessManager(self)

    @QtCore.pyqtSlot()
    def on_loadFinished(self):
        self.initialized = True

    def waitUntilReady(self):
        if not self.initialized:
            loop = QtCore.QEventLoop()
            self.loadFinished.connect(loop.quit)
            loop.exec_()

    def geocode(self, location):
        return GeoCoder(self).geocode(location, self._api_key)

    def centerAtAddress(self, location):
        try:
            latitude, longitude = self.geocode(location)
        except GeoCoder.NotFoundError:
            print("Not found {}".format(location))
            return None, None
        self.centerAt(latitude, longitude)
        return latitude, longitude

    def addMarkerAtAddress(self, location, **extra):
        if 'title' not in extra:
            extra['title'] = location
        try:
            latitude, longitude = self.geocode(location)
        except GeoCoder.NotFoundError:
            return None
        return self.addMarker(location, latitude, longitude, **extra)

    @QtCore.pyqtSlot(float, float)
    def mapIsMoved(self, lat, lng):
        self.mapMoved.emit(lat, lng)

    @QtCore.pyqtSlot(float, float)
    def mapIsClicked(self, lat, lng):
        self.mapClicked.emit(lat, lng)

    @QtCore.pyqtSlot(float, float)
    def mapIsRightClicked(self, lat, lng):
        self.mapRightClicked.emit(lat, lng)

    @QtCore.pyqtSlot(float, float)
    def mapIsDoubleClicked(self, lat, lng):
        self.mapDoubleClicked.emit(lat, lng)

    # markers
    @QtCore.pyqtSlot(str, float, float)
    def markerIsMoved(self, key, lat, lng):
        self.markerMoved.emit(key, lat, lng)

    @QtCore.pyqtSlot(str, float, float)
    def markerIsClicked(self, key, lat, lng):
        self.markerClicked.emit(key, lat, lng)

    @QtCore.pyqtSlot(str, float, float)
    def markerIsRightClicked(self, key, lat, lng):
        self.markerRightClicked.emit(key, lat, lng)

    @QtCore.pyqtSlot(str, float, float)
    def markerIsDoubleClicked(self, key, lat, lng):
        self.markerDoubleClicked.emit(key, lat, lng)

    def runScript(self, script, callback=None):
        if callback is None:
            self.page().runJavaScript(script)
        else:
            self.page().runJavaScript(script, callback)

    def centerAt(self, latitude, longitude):
        self.runScript("gmap_setCenter({},{})".format(latitude, longitude))

    def center(self):
        self._center = {}
        loop = QtCore.QEventLoop()

        def callback(*args):
            self._center = tuple(args[0])
            loop.quit()

        self.runScript("gmap_getCenter()", callback)
        loop.exec_()
        return self._center

    def setZoom(self, zoom):
        self.runScript("gmap_setZoom({})".format(zoom))

    def addMarker(self, key, latitude, longitude, **extra):
        return self.runScript(
            "gmap_addMarker("
            "key={!r}, "
            "latitude={}, "
            "longitude={}, "
            "{}"
            "); ".format(key, latitude, longitude, json.dumps(extra)))

    def moveMarker(self, key, latitude, longitude):
        return self.runScript(
            "gmap_moveMarker({!r}, {}, {});".format(key, latitude, longitude))

    def setMarkerOptions(self, keys, **extra):
        return self.runScript(
            "gmap_changeMarker("
            "key={!r}, "
            "{}"
            "); "
                .format(keys, json.dumps(extra)))

    def deleteMarker(self, key):
        return self.runScript(
            "gmap_deleteMarker("
            "key={!r} "
            "); ".format(key))


if __name__ == '__main__':
    import sys

    API_KEY = "YOUR_API_KEY_HERE"

    app = QtWidgets.QApplication(sys.argv)
    w = QGoogleMap(api_key=API_KEY)
    w.resize(640, 480)
    w.show()
    w.waitUntilReady()
    w.setZoom(14)
    lat, lng = w.centerAtAddress("Lima Peru")
    if lat is None and lng is None:
        lat, lng = -12.0463731, -77.042754
        w.centerAt(lat, lng)

    w.addMarker("MyDragableMark", lat, lng, **dict(
        icon="http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_red.png",
        draggable=True,
        title="Move me!"
    ))

    for place in ["Plaza Ramon Castilla", "Plaza San Martin", ]:
        w.addMarkerAtAddress(place, icon="http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_gray.png")

    w.mapMoved.connect(print)
    w.mapClicked.connect(print)
    w.mapRightClicked.connect(print)
    w.mapDoubleClicked.connect(print)
    sys.exit(app.exec_())

立即使用经过测试的版本更新我的存储库:-)

Soon update my repository with a tested version :-)

这篇关于如何在pyqt5中创建小部件以显示Google Map的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆