简体   繁体   English

从JS将鼠标单击保存到PyQt5

[英]storing lat long on mouse click from JS to PyQt5

I'm trying to store lat/lng on mouse click to geometry Point. 我正在尝试在鼠标单击到几何点时存储经纬度。 So basically when user clicks on map i need to get those coordinates(lat/lng) and store them to variable for example point = Point(lat, lng) so i can calculate nearest geometry and pull data from PostGIS. 因此,基本上,当用户单击地图时,我需要获取那些坐标(纬度/经度)并将其存储到变量中,例如point = Point(lat, lng)以便我可以计算最近的几何图形并从PostGIS中提取数据。

I'm aware i need to establish backend and @pyqtSlot(float,float) , but since im new to this i cant get it to work. 我知道我需要建立后端和@pyqtSlot(float,float) ,但是由于这是我的新手,因此我无法使其正常工作。 I have this code that is generated by QtDesigner and you dont have to bother with all the buttons. 我有QtDesigner生成的这段代码,您不必理会所有按钮。 Here is the HTML/JS part: 这是HTML / JS部分:

maphtml = '''
    <!DOCTYPE HTML>
    <html>
    <head>
    <meta name="robots" content="index, all" />    
    <script src="qrc:///qtwebchannel/qwebchannel.js"></script>
    <title>WebGL Earth API - Side-by-side - Basic Leaflet 
    compatibility</title>
    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet- 
    0.7.2/leaflet.css" />
    <script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
    <script src="http://www.webglearth.com/v2/api.js"></script>
    <script src="scripts/qwebchannel.js"></script>
    <script>
    var backend;
    new QWebChannel(qt.webChannelTransport, function (channel) {
    backend = channel.objects.backend;


    });
    function init() {
    var m = {};

    start_(L, 'L');
    start_(WE, 'WE');

    function start_(API, suffix) {
    var mapDiv = 'map' + suffix;
    var map = API.map(mapDiv, {
    center: [51.505, -0.09],
    zoom: 4,
    dragging: true,
    scrollWheelZoom: true,
    proxyHost: 'http://srtm.webglearth.com/cgi-bin/corsproxy.fcgi?url='
    });
    m[suffix] = map;

    //Add baselayer
    API.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
    attribution: '© OpenStreetMap contributors'
    }).addTo(map);

    //Add TileJSON overlay
    var json = {"profile": "mercator", "name": "Grand Canyon USGS", "format": 
    "png", "bounds": [15.976953506469728, 45.813157465613884], "minzoom": 10, 
    "version": "1.0.0", "maxzoom": 16, "center": [15.976953506469728, 
    45.813157465613884, 16], "type": "overlay", "description": "", 
    "basename": 
    "grandcanyon", "tilejson": "2.0.0", "sheme": "xyz", "tiles": 
    ["http://tileserver.maptiler.com/grandcanyon/{z}/{x}/{y}.png"]};
    if (API.tileLayerJSON) {
    var overlay2 = API.tileLayerJSON(json, map);
    } else {
    //If not able to display the overlay, at least move to the same location
    map.setView([json.center[1], json.center[0]], json.center[2]);
    }



    //Print coordinates of the mouse
    map.on('click', function(e) {

    document.getElementById('coords').innerHTML = e.latlng.lat + ', ' + 
    e.latlng.lng;
    backend.foo(e.latlng.lat,e.latlng.lng)

    });
    }

    //Synchronize view
    m['L'].on('click', function(e) {
    var center = m['L'].getCenter();
    var zoom = m['L'].getZoom();
    m['WE'].setView([center['lat'], center['lng']], zoom);
    });
    }
    </script>
    <style>
    html, body{padding: 0; margin: 0; overflow: hidden;}
    #mapL, #mapWE {position:absolute !important; top: 0; right: 0; bottom: 0; 
    left: 0;
    background-color: #fff; position: absolute !important;}
    #mapL {right: 0%;}
    #mapWE {left: 100%;}
    #coords {position: absolute; bottom: 0;}
    </style>
    </head>
    <body onload="javascript:init()">
    <div id="mapL"></div>
    <div id="mapWE"></div>
    <div id="coords"></div>
    </body>
    </html>
    '''

And here is PyQt code, they are all in same .py btw. 这是PyQt代码,它们都在同一.py btw中。 At the start i have Backend() that should be doin its job. 首先,我应该在其工作中使用Backend() You can skip to def setupUI and to self.mapa = QtWidgets.QWidget(self.centralwidget) to see where i call Backend() : 您可以跳过以def setupUI并跳转到self.mapa = QtWidgets.QWidget(self.centralwidget)来查看我在哪里调用Backend()

class Backend(QObject):
    @pyqtSlot(float,float)
    def foo(self, lat,lng):
        global x,y
        x=lng
        y=lat
        print(lat, lng)

class Ui_MainWindow(object):

    def selected(self, text):
        self.selected_text = text
        return self.selected_text

    def connecti(self):
        try:
            engine = 
     create_engine('postgresql://postgres:hrvatina@localhost:5432/Diplomski')
            self.connection = engine.connect()

            return QMessageBox.information(None, "Uspješna konekcija", 
     "Spojeni ste na bazu")
        except:

            return QMessageBox.critical(None, "Pogreška", "Neuspješno 
     spajanje na bazu")


    def odabir(self):

        try:

            broj = self.link.text()

            self.comboBox.activated[str].connect(self.selected)

            value = str(self.comboBox.currentText())
            if self.pon.isChecked():
                radio = str(self.pon.text())
                print(radio)
            elif self.uto.isChecked():
                radio = str(self.uto.text())
                print(radio)
            elif self.sri.isChecked():
                radio = str(self.sri.text())
                print(radio)
            elif self.cet.isChecked():
                radio = str(self.cet.text())
                print(radio)
            elif self.pet.isChecked():
                radio = str(self.pet.text())
                print(radio)
            elif self.sub.isChecked():
                radio = str(self.sub.text())
                print(radio)
            elif self.ned.isChecked():
                radio = str(self.ned.text())
                print(radio)


            query ='SELECT * FROM ' + radio + '_' + value + ' where "IdLink" 
     = %s' % (broj)

            df = pd.read_sql_query(query, con=self.connection, params= 
     {'link': '%' + broj + '%'})
            df = df.transpose()

            hf = df.join(df.iloc[:, 0].str.split(';', 3, 
    expand=True).rename(columns={0: 'mean', 1: 'median', 2: 'std'}))


            g = hf.drop(hf.columns[[0]], axis=1)

            hm = g.drop(g.index[[0]])

            prva1 = hm.apply(pd.to_numeric, errors='coerce')

            #Izračun srednjih vrijednosti
            mean=prva1['mean'].mean()
            self.mean.setText(str(mean))
            median=prva1['median'].mean()
            self.median.setText(str(median))
            std=prva1['std'].mean()
            self.std.setText(str(std))

            upper_bound = go.Scatter(
                name='Gornja granica',
                x=prva1.index.to_native_types(),
                y=prva1['mean'] + prva1['std'],
                mode='lines',
                marker=dict(color="028F1E"),
                line=dict(width=1, color="028F1E"),
                fillcolor='rgba(68, 68, 68, 0.3)',

                fill='tonexty')

            trace = go.Scatter(
                name='Srednja vrijednost',
                x=prva1.index.to_native_types(),
                y=prva1['mean'],
                mode='lines',
                line=dict(color='rgb(31, 119, 180)'),
                fillcolor='rgba(68, 68, 68, 0.3)',
                fill='tonexty')

            lower_bound = go.Scatter(
                name='Donja granica',
                x=prva1.index.to_native_types(),
                y=prva1['mean'] - prva1['std'],
                marker=dict(color="9B111E"),
                line=dict(width=1, color="9B111E"),
                mode='lines')

            data = [lower_bound, trace, upper_bound]

            layout = go.Layout(
                xaxis=dict(
                    title='AXIS TITLE',
                    titlefont=dict(
                        family='Arial, sans-serif',
                        size=18,
                        color='lightgrey'
                    ),
                    showticklabels=True,
                    tickangle=45,
                    tickfont=dict(
                        family='Old Standard TT, serif',
                        size=14,
                        color='black'
                    ),
                    exponentformat='e',
                    showexponent='All'
                ),
                yaxis=dict(title='Brzina (km/h)'),
                title='Minutni interval za ' + radio + ' sa standardnom 
          devijacijom za ' + broj,
            )

            fig = go.Figure(data=data, layout=layout)
            raw_html = '<html><head><meta charset="utf-8" />'
            raw_html += '<script src="https://cdn.plot.ly/plotly- 
    latest.min.js"></script></head>'
            raw_html += '<body>'
            raw_html += plotly.offline.plot(fig, include_plotlyjs=False, 
    output_type='div')
            raw_html += '</body></html>'

            #PLOTLY
            self.graf.setHtml(raw_html)

        except:

            return QMessageBox.critical(None, "Pogreška", "Podaci za odabrane 
            opcije ne postoje!")
    def setupUi(self, MainWindow):

        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(978, 704)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.formLayout = QtWidgets.QFormLayout(self.centralwidget)
        self.formLayout.setObjectName("formLayout")
        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")
        self.gumb_spoji = QtWidgets.QPushButton(self.centralwidget)
        self.gumb_spoji.setObjectName("gumb_spoji")

        # Spoji se na bazu
        self.gumb_spoji.clicked.connect(self.connecti)
        engine = 
        self.verticalLayout.addWidget(self.gumb_spoji)
        self.link = QtWidgets.QLineEdit(self.centralwidget)
        self.link.setObjectName("link")
        self.verticalLayout.addWidget(self.link)
        self.pon = QtWidgets.QRadioButton(self.centralwidget)
        self.pon.setObjectName("pon")
        self.verticalLayout.addWidget(self.pon)
        self.uto = QtWidgets.QRadioButton(self.centralwidget)
        self.uto.setObjectName("uto")
        self.verticalLayout.addWidget(self.uto)
        self.sri = QtWidgets.QRadioButton(self.centralwidget)
        self.sri.setObjectName("sri")
        self.verticalLayout.addWidget(self.sri)
        self.cet = QtWidgets.QRadioButton(self.centralwidget)
        self.cet.setObjectName("cet")
        self.verticalLayout.addWidget(self.cet)
        self.pet = QtWidgets.QRadioButton(self.centralwidget)
        self.pet.setObjectName("pet")
        self.verticalLayout.addWidget(self.pet)
        self.sub = QtWidgets.QRadioButton(self.centralwidget)
        self.sub.setObjectName("sub")
        self.verticalLayout.addWidget(self.sub)
        self.ned = QtWidgets.QRadioButton(self.centralwidget)
        self.ned.setObjectName("ned")
        self.verticalLayout.addWidget(self.ned)
        self.comboBox = QtWidgets.QComboBox(self.centralwidget)
        self.comboBox.setObjectName("comboBox")
        self.comboBox.addItem("")
        self.comboBox.addItem("")
        self.verticalLayout.addWidget(self.comboBox)
        self.gumb_dohvati = QtWidgets.QPushButton(self.centralwidget)
        self.gumb_dohvati.setObjectName("gumb_dohvati")

        # Dohvati podatke
        self.gumb_dohvati.clicked.connect(self.odabir)

        self.verticalLayout.addWidget(self.gumb_dohvati)
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setObjectName("label")
        self.verticalLayout.addWidget(self.label)
        self.mean = QtWidgets.QLineEdit(self.centralwidget)
        self.mean.setObjectName("mean")
        self.verticalLayout.addWidget(self.mean)
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setObjectName("label_2")
        self.verticalLayout.addWidget(self.label_2)
        self.median = QtWidgets.QLineEdit(self.centralwidget)
        self.median.setObjectName("median")
        self.verticalLayout.addWidget(self.median)
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setObjectName("label_3")
        self.verticalLayout.addWidget(self.label_3)
        self.std = QtWidgets.QLineEdit(self.centralwidget)
        self.std.setObjectName("std")
        self.verticalLayout.addWidget(self.std)
        self.formLayout.setLayout(0, QtWidgets.QFormLayout.LabelRole, 
        self.verticalLayout)

        # I want to pass lat/lng here and after user click show data in 
        Qwidget below, but i will do that on my own i just need those lat/lng 
        after every click
        self.mapa = QtWidgets.QWidget(self.centralwidget)
        self.mapa.setObjectName("mapa")
        backend = Backend()
        channel = QWebChannel()
        channel.registerObject('backend', backend)

        self.mapa = QWebEngineView()
        self.mapa.page().setWebChannel(channel)

        self.mapa.setHtml(maphtml)

        point=Point(y,x)





        #sql = 'select * from geo'
        #df = gpd.GeoDataFrame.from_postgis(sql, self.connection, 
 geom_col='geometry' )
        #def min_dist(point, gpd2):
            #df['Dist'] = df.apply(lambda row:  
 point.distance(row.geometry),axis=1)
            #geoseries = df.iloc[gpd2['Dist'].idxmin()]
            #return geoseries['IdLink']
        #point=Point(self.Backend.lat(),self.Backend.lng())
        #self.brojka=min_dist(point,df)

        self.formLayout_3 = QtWidgets.QFormLayout(self.mapa)
        self.formLayout_3.setObjectName("formLayout_3")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, 
        self.mapa)
        self.graf = QtWidgets.QWidget(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, 
        QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(255)

   sizePolicy.setHeightForWidth(self.graf.sizePolicy().hasHeightForWidth())
        self.graf.setSizePolicy(sizePolicy)
        self.graf.setMouseTracking(True)
        self.graf.setObjectName("graf")
        self.graf = QWebEngineView(self.centralwidget)
        self.formLayout_2 = QtWidgets.QFormLayout(self.graf)
        self.formLayout_2.setObjectName("formLayout_2")
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.SpanningRole, 
        self.graf)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 978, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.gumb_spoji.setText(_translate("MainWindow", "Spoji se na bazu"))
        self.pon.setText(_translate("MainWindow", "Ponedjeljak"))
        self.uto.setText(_translate("MainWindow", "Utorak"))
        self.sri.setText(_translate("MainWindow", "Srijeda"))
        self.cet.setText(_translate("MainWindow", "Cetvrtak"))
        self.pet.setText(_translate("MainWindow", "Petak"))
        self.sub.setText(_translate("MainWindow", "Subota"))
        self.ned.setText(_translate("MainWindow", "Nedjelja"))
        self.comboBox.setItemText(0, _translate("MainWindow", "5min"))
        self.comboBox.setItemText(1, _translate("MainWindow", "15min"))
        self.gumb_dohvati.setText(_translate("MainWindow", "Dohvati 
        podatke"))
        self.label.setText(_translate("MainWindow", "Srednja vrijednost"))
        self.label_2.setText(_translate("MainWindow", "Median"))
        self.label_3.setText(_translate("MainWindow", "Standardna 
        devijacija"))


if __name__ == "__main__":
    import sys
    app = QtCore.QCoreApplication.instance()
    if app is None:
        app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()

    sys.exit(app.exec_())

I saw similar questions but couldn't make it work so far... In PyQt4 i have it almost working, but since i am bad at JS, i dont know how to to return lat/lng intead of getCenter().lat from this code: 我看到了类似的问题,但到目前为止还无法解决...在PyQt4中,它几乎可以正常工作,但是由于我对JS不好,所以我不知道如何从getCenter()。lat返回lat / lng intead此代码:

 if(typeof MainWindow != 'undefined') { var onMapMove = function(e) { MainWindow.onMapMove(map.getCenter().lat, map.getCenter().lng) }; map.on('click', onMapMove); onMapMove(); 

I can not work much with your code because it is badly formatted and there are missing elements to define so my answer will be based on showing you an example. 由于您的代码格式不正确,并且缺少定义的元素,因此我不能做很多工作,因此我的答案将基于向您展示一个示例。

First of all it does not put all the code in a file, that makes it difficult to maintain the code, in this case I have divided into the following files: 首先,它不会将所有代码都放在一个文件中,这使得很难维护代码,在这种情况下,我将其分为以下文件:

.
├── index.html
├── main.py
├── utils.css
└── utils.js

 window.onload = function() { new QWebChannel(qt.webChannelTransport, function (channel) { window.backend = channel.objects.backend; }); var m = {}; start_(L, 'L'); start_(WE, 'WE'); function start_(API, suffix) { var mapDiv = 'map' + suffix; var map = API.map(mapDiv, { center: [51.505, -0.09], zoom: 4, dragging: true, scrollWheelZoom: true, proxyHost: 'http://srtm.webglearth.com/cgi-bin/corsproxy.fcgi?url=' }); m[suffix] = map; //Add baselayer API.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map); //Add TileJSON overlay var json = { "profile": "mercator", "name": "Grand Canyon USGS", "format": "png", "bounds": [15.976953506469728, 45.813157465613884], "minzoom": 10, "version": "1.0.0", "maxzoom": 16, "center": [15.976953506469728, 45.813157465613884, 16 ], "type": "overlay", "description": "", "basename": "grandcanyon", "tilejson": "2.0.0", "sheme": "xyz", "tiles": ["http://tileserver.maptiler.com/grandcanyon/{z}/{x}/{y}.png"] }; if (API.tileLayerJSON) { var overlay2 = API.tileLayerJSON(json, map); } else { //If not able to display the overlay, at least move to the same location map.setView([json.center[1], json.center[0]], json.center[2]); } //Print coordinates of the mouse map.on('click', function(e) { document.getElementById('coords').innerHTML = e.latlng.lat + ', ' + e.latlng.lng; backend.pointClicked(e.latlng.lat, e.latlng.lng); }); } //Synchronize view m['L'].on('click', function(e) { var center = m['L'].getCenter(); var zoom = m['L'].getZoom(); m['WE'].setView([center['lat'], center['lng']], zoom); }); } 
 html, body { padding: 0; margin: 0; overflow: hidden; } #mapL, #mapWE { position: absolute !important; top: 0; right: 0; bottom: 0; left: 0; background-color: #fff; position: absolute !important; } #mapL { right: 0%; } #mapWE { left: 100%; } #coords { position: absolute; bottom: 0; } 
 <!DOCTYPE HTML> <html> <head> <meta name="robots" content="index, all"/> <title>WebGL Earth API - Side-by-side - Basic Leaflet compatibility </title> <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css"/> <link rel="stylesheet" href="utils.css"/> <script src="qrc:///qtwebchannel/qwebchannel.js"></script> <script type="text/javascript" src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script> <script type="text/javascript" src="http://www.webglearth.com/v2/api.js"></script> <script type="text/javascript" src="utils.js"> </script> </head> <body> <div id="mapL"></div> <div id="mapWE"></div> <div id="coords"></div> </body> </html> 

main.py main.py

from PyQt5 import QtWebEngineWidgets, QtWidgets, QtCore, QtWebChannel

class Backend(QtCore.QObject):
    pointChanged = QtCore.pyqtSignal(float, float)

    @QtCore.pyqtSlot(float,float)
    def pointClicked(self, x, y):
        self.pointChanged.emit(x, y)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        map_view = QtWebEngineWidgets.QWebEngineView()

        backend = Backend(self)
        backend.pointChanged.connect(self.onPointChanged)
        channel = QtWebChannel.QWebChannel(self)
        channel.registerObject('backend', backend)
        map_view.page().setWebChannel(channel)

        file = QtCore.QDir.current().absoluteFilePath("index.html")
        map_view.load(QtCore.QUrl.fromLocalFile(file))

        self.setCentralWidget(map_view)

    @QtCore.pyqtSlot(float,float)
    def onPointChanged(self, x, y):
        print("new points")
        print(x, y)


if __name__ == '__main__':
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

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

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