#python #pyqt5 #signals #slot
#python #pyqt5 #сигналы #слот
Вопрос:
Мне нужно отобразить карту в моем приложении pyqt5. Перепробовав множество вариантов, я пришел к выводу, что использование leaflet js — мой лучший выбор. Я создал простой пользовательский интерфейс в Qt designer и подключил пользовательский интерфейс в index.py
:
import sys
import os.path
from os import environ
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.uic import loadUiType
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
ui,_=loadUiType('user_interface.ui')
def suppress_qt_warnings():
environ["QT_DEVICE_PIXEL_RATIO"] = "0"
environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
environ["QT_SCREEN_SCALE_FACTORS"] = "1"
environ["QT_SCALE_FACTOR"] = "1"
class MainApp(QMainWindow, ui):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
def main():
suppress_qt_warnings()
app=QApplication(sys.argv)
QApplication.processEvents()
window = MainApp()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
В пользовательском интерфейсе есть продвигаемый виджет под названием leafwidget со следующим кодом для отображения моей карты листовки (leafwidget.py ):
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtWebChannel import QWebChannel
class WebEnginePage(QWebEnginePage):
def javaScriptConsoleMessage(self, level, message, lineNumber, sourceID):
print("javaScriptConsoleMessage: ", level, message, lineNumber, sourceID)
class LeafWidget (QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.browser = QWebEngineView()
self.browser.settings().setAttribute(QWebEngineSettings.JavascriptEnabled, True)
self.browser.setPage(WebEnginePage(self.browser))
self.browser.load(QUrl.fromLocalFile(QDir.current().absoluteFilePath('mymap.html')))
self.browser.loadFinished.connect(self.onLoadFinished)
self.channel = QWebChannel()
self.handler = CallHandler()
self.channel.registerObject('jsHelper', self.handler)
self.browser.page().setWebChannel(self.channel)
lay = QVBoxLayout(self)
lay.addWidget(self.browser)
def onLoadFinished(self, ok):
if ok:
self.browser.page().runJavaScript("")
class CallHandler(QObject):
@pyqtSlot(int)
def logMapId(self, ID1):
print('callback received', ID1)
Как вы можете видеть в этом коде, я фактически загружаю mymap.html
файл с картой листовки и некоторым javascript для оформления и загрузки файла geojson. Вот мой html-код:
<!DOCTYPE html>
<head>
<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="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript">
var backend;
new QWebChannel(qt.webChannelTransport, function(channel) {
backend = channel.objects.jsHelper;
})
</script>
<style>
#my-map {
width:1200px;
height:450px;
}
</style>
</head>
<body>
<div id="my-map"></div>
<script>
var osmUrl1 = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png';
var grayscale = L.tileLayer(osmUrl1, {id: 'MapID', attribution:'1'});
var baseMaps = {
"Grayscale": grayscale,
};
var myStyle = {
"color": "blue",
"weight": 4,
};
$.getJSON("roadway.geojson", function(data) {
var geojson = L.geoJson(data, {
style: myStyle,
onEachFeature: function (feature, layer) {
layer.on('click', function (e) {
backend.logMapId(feature.properties.ID1)
});
},
});
var map = L.map('my-map')
.fitBounds(geojson.getBounds());
var overlayMaps = {
"net": geojson
};
grayscale.addTo(map)
geojson.addTo(map);
L.control.layers(baseMaps, overlayMaps).addTo(map);
});
</script>
</body>
</html>
Ключевым моментом, на который следует обратить внимание, является событие click, которое возвращает идентификатор строки, на которой нажата строка слоя geiojson, используя QWebChannel
to leafwidget.py
. Затем leafwidget.py
я получаю идентификатор строки, на которую нажали, используя слот внутри CallHandler
класса. Все работает хорошо, и я вижу напечатанные значения идентификаторов в консоли каждый раз, когда я нажимаю на строку.
Теперь последний шаг — передать каждый идентификатор ссылки в мой index.py а затем отобразить в a listview
или что-то в этом роде. Я думал определить сигнал внутри CallHandler
класса и выдавать идентификатор строки каждый раз, когда строка щелкается на карте и принимается CallHandler
. Затем получите переданное значение в слоте в моем index.py и добавьте к listview
этому . Я не уверен, как это сделать?
Ответ №1:
Это тривиальная задача, на которую вы ответили сами: используйте сигналы, поскольку они позволяют вам обмениваться информацией между объектами асинхронно. С другой стороны, концепция модуля или файла .py имеет смысл только при организации классов, функций и т. Д., Но она не вмешивается в саму операцию, поскольку это происходит между взаимодействием объектов.
class CallHandler(QObject):
geojson_clicked = pyqtSignal(int)
@pyqtSlot(int)
def logMapId(self, ID1):
self.geojson_clicked.emit(ID1)
class MainApp(QMainWindow, ui):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
self.LeafWidget.handler.geojson_clicked.connect(self.handle_geojson_clicked)
def handle_geojson_clicked(self, id_):
self.statusBar().showMessage("{} clicked".format(id_))
Комментарии:
1. У меня было почти все правильно, только соединение в моем mainapp не работало. Я вызывал
CallHandler
класс .. упс.. Я думаю, мне нужно потратить больше времени на некоторые базовые концепции. В любом случае спасибо.