OpenLayers Geolocation in PyQt 5.9

不问归期 提交于 2019-11-27 08:34:43

问题


I've implemented a Website with a geolocation function and Button.

This Webpage gets displayed fine in a QwebEngineView (OSM Map too). The Webpage is loaded

def __init__(self, parent=None):
        super(MainGUI, self).__init__(parent)
        self.ui = uic.loadUi("GPS.ui", self)
        self.ui.w3View.load(QtCore.QUrl('file:///Map.html'))

All native OpenLayers Buttons (Zoom IN and OUT) are working fine.

I created a new custom button to display my geolocation on the OpenLayers Map.

This is the function im using to geolocate me:

var handleGeolocation = function() {

      var coordinates;
      var geolocation = new ol.Geolocation({
        projection: view.getProjection(),
        tracking: true
      });
      // handle geolocation error.
      geolocation.on('error', function (error) {
        var info = document.getElementById('info');
        info.innerHTML = error.message;
        info.style.display = '';
      });

      var accuracyFeature = new ol.Feature();
      geolocation.on('change:accuracyGeometry', function () {
        accuracyFeature.setGeometry(geolocation.getAccuracyGeometry());
      });

      var positionFeature = new ol.Feature();
      positionFeature.setStyle(new ol.style.Style({
        image: new ol.style.Circle({
          radius: 6,
          fill: new ol.style.Fill({
            color: '#3399CC'
          }),
          stroke: new ol.style.Stroke({
            color: '#fff',
            width: 2
          })
        })
      }));

      geolocation.once('change:position', function () {
        coordinates = geolocation.getPosition();
        positionFeature.setGeometry(coordinates ?
          new ol.geom.Point(coordinates) : null);
        map.getView().setCenter(coordinates);
        map.getView().setZoom(17);
      });

      new ol.layer.Vector({
        map: map,
        source: new ol.source.Vector({
          features: [accuracyFeature, positionFeature]
        })
      });
    }

I created the Button with the help from here.

the whole Webpage looks like this:

<!DOCTYPE html>
<html>
  <head>
    <title>Accessible Map</title>
    <link rel="stylesheet" href="https://openlayers.org/en/v4.2.0/css/ol.css" type="text/css">
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
    <script src="https://openlayers.org/en/v4.2.0/build/ol-debug.js"></script>
   <style>
      a.skiplink {
        position: absolute;
        clip: rect(1px, 1px, 1px, 1px);
        padding: 0;
        border: 0;
        height: 1px;
        width: 1px;
        overflow: hidden;
      }
      a.skiplink:focus {
        clip: auto;
        height: auto;
        width: auto;
        background-color: #fff;
        padding: 0.3em;
      }
      #map:focus {
        outline: #4A74A8 solid 0.15em;
      }
      map{
          max-width: 760 px;
          max-height: 50 px;
      }

      .geoButton {
        top: 80px;
        left: .5em;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map" tabindex="0"></div>
    <script>
      window.app = {};
      var app = window.app;


      view = new ol.View({
        center: [0, 0],
        zoom: 2
      });

      app.getLocation = function(opt_options) {
        var options = opt_options || {};

        var geoButton = document.createElement('button');
        geoButton.innerHTML = 'L';

        var handleGeolocation = function() {
          /*    var isMobile =  {
              Android: function () {
                return navigator.userAgent.match(/Android/i);
              },
              BlackBerry: function () {
                return navigator.userAgent.match(/BlackBerry/i);
              },
              iOS: function () {
                return navigator.userAgent.match(/iPhone|iPod|iPad/i);
              },
              Opera: function () {
                return navigator.userAgent.match(/Opera Mini/i);
              },
              Windows: function () {
                return navigator.userAgent.match(/IEMobile/i);
              },
              any: function () {
                return ((isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows()));
              }
            };

            if (isMobile.any()){
              geolocation.setTrackingOptions(enableHighAccuracy );
            } */

          var coordinates;
          var geolocation = new ol.Geolocation({
            projection: view.getProjection(),
            tracking: true
          });
          // handle geolocation error.
          geolocation.on('error', function (error) {
            var info = document.getElementById('info');
            info.innerHTML = error.message;
            info.style.display = '';
          });

          var accuracyFeature = new ol.Feature();
          geolocation.on('change:accuracyGeometry', function () {
            accuracyFeature.setGeometry(geolocation.getAccuracyGeometry());
          });

          var positionFeature = new ol.Feature();
          positionFeature.setStyle(new ol.style.Style({
            image: new ol.style.Circle({
              radius: 6,
              fill: new ol.style.Fill({
                color: '#3399CC'
              }),
              stroke: new ol.style.Stroke({
                color: '#fff',
                width: 2
              })
            })
          }));

          geolocation.once('change:position', function () {
            coordinates = geolocation.getPosition();
            positionFeature.setGeometry(coordinates ?
              new ol.geom.Point(coordinates) : null);
            map.getView().setCenter(coordinates);
            map.getView().setZoom(17);
          });

          new ol.layer.Vector({
            map: map,
            source: new ol.source.Vector({
              features: [accuracyFeature, positionFeature]
            })
          });
        }

        geoButton.addEventListener('click', handleGeolocation, false);
        geoButton.addEventListener('touchstart', handleGeolocation, false);

        var element = document.createElement('div');
        element.className = 'ol-unselectable ol-control geoButton';
        element.appendChild(geoButton);

        ol.control.Control.call(this, {
          element: element,
          target: options.target
        });

      };

      ol.inherits(app.getLocation, ol.control.Control);
      //Standard Initialisierung


      // Geolocation function



      var map = new ol.Map({
        layers: [
          new ol.layer.Tile({
            source: new ol.source.OSM()
          })
        ],
        target: 'map',
        controls: ol.control.defaults({
          attributionOptions: /** @type {olx.control.AttributionOptions} */ ({
            collapsible: false
          })
        }).extend([new app.getLocation()]),
        view: view
      });

      //Display Input Datastream
    </script>
  </body>
</html>

Inside a normal browser it's working fine but not inside my PyQt app. After clicking the custom Button nothing happens.

What am i doing wrong or is not possible?


回答1:


The main problem is to enable the permissions, if you run in a browser like Firefox, Chrome, etc. will show you a popup asking you to accept or not the GeoLocation permission.

In this case it must be enabled by code, for this the QWebEnginePage emits a signal every time authorization is required, it does this through the signal featurePermissionRequested, we connect it to some slot and we enable the permission with the function setFeaturePermission().

    self.ui.w3View..page().featurePermissionRequested.connect(self.onFeaturePermissionRequested)

def onFeaturePermissionRequested(self, securityOrigin, feature):
    self.sender().setFeaturePermission(securityOrigin,
                                     QWebEnginePage.Geolocation,
                                     QWebEnginePage.PermissionGrantedByUser)

Note: In linux I still have problems with the GeoClude provider, the error message is as follows:

Failed to set Geoclue positioning requirements. Geoclue error: org.qtproject.QtDBus.Error.InvalidObjectPath




回答2:


Adding the following lines solved my Problems:

    self.ui.w3View.page().featurePermissionRequested.connect(self.permissionRequested)

def permissionRequested(self, frame, feature):
    self.ui.w3View.page().setFeaturePermission(frame, feature, QtWebEngineWidgets.QWebEnginePage.PermissionGrantedByUser)

Found it in this post and editing it to PyQt 5.9.



来源:https://stackoverflow.com/questions/45689597/openlayers-geolocation-in-pyqt-5-9

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!