我对编码、python 和 pyside6 很陌生。我花了几个月的时间得到下面的代码,看起来效果很好。
我尝试了很多不同的方法来实现一些非常简单的事情(我认为)。我想访问 PandasModel 类中名为 self.filtered_df 的数据框。我希望此访问位于 MainWindow 类中的 def display_filtered_map(self): 中。
这是完整的代码
from PySide6.QtWidgets import QMainWindow, QApplication, QTableView, QLineEdit, QVBoxLayout, QWidget
from PySide6.QtCore import QAbstractTableModel, Qt, QModelIndex
from PySide6.QtWebEngineWidgets import QWebEngineView
import sys
import os
import sqlite3
import pandas as pd
import folium
from folium.plugins import FastMarkerCluster
from folium import LatLngPopup
from jinja2 import Template
from ui.vrpsselect_window import Ui_mw_Main
# code snippet from here: https://stackoverflow.com/questions/73481046/how-to-overide-a-feature-method-in-folium
class GetLatLngPopup(LatLngPopup):
_template = Template(u"""
{% macro script(this, kwargs) %}
var {{this.get_name()}} = L.popup();
function latLngPop(e) {
{{this.get_name()}}
.setLatLng(e.latlng)
.setContent("Latitude: " + e.latlng.lat.toFixed(6) +
"<br>Longitude: " + e.latlng.lng.toFixed(6))
.openOn({{this._parent.get_name()}});
}
{{this._parent.get_name()}}.on('click', latLngPop);
{% endmacro %}
""")
def __init__(self):
super(GetLatLngPopup, self).__init__()
self._name = 'GetLatLngPopup'
class PandasModel(QAbstractTableModel):
def __init__(self, dataframe: pd.DataFrame, parent=None):
super().__init__(parent)
self._dataframe = dataframe
self.filtered_df = dataframe.copy() # Initialize filtered DataFrame
def rowCount(self, parent=QModelIndex()) -> int:
if parent == QModelIndex():
return len(self.filtered_df)
return 0
def columnCount(self, parent=QModelIndex()) -> int:
if parent == QModelIndex():
return len(self.filtered_df.columns)
return 0
def data(self, index: QModelIndex, role=Qt.ItemDataRole):
if not index.isValid():
return None
if role == Qt.DisplayRole:
return str(self.filtered_df.iloc[index.row(), index.column()])
return None
def headerData(self, section: int, orientation: Qt.Orientation, role: Qt.ItemDataRole):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
return str(self.filtered_df.columns[section])
if orientation == Qt.Vertical:
return str(self.filtered_df.index[section])
return None
def filter_data(self, country_text: str, name_text: str, ident_text: str, airport_text: str):
country_filter = self._dataframe['Country'].str.contains(country_text, case=False)
name_filter = self._dataframe['Name'].str.contains(name_text, case=False)
ident_filter = self._dataframe['Ident'].str.contains(ident_text, case=False)
airport_filter = self._dataframe['Airport'].str.contains(airport_text, case=False)
self.filtered_df = self._dataframe[country_filter & name_filter & ident_filter & airport_filter]
self.layoutChanged.emit() # Update the view
class MainWindow(QMainWindow, Ui_mw_Main):
def __init__(self):
super().__init__()
self.setupUi(self)
# run on startup
self.setup()
self.load_database()
model = PandasModel(self.df)
self.tv_RP.setModel(model)
self.initialise()
# signals
self.pb_Close.clicked.connect(self.close)
self.le_SearchCountry.textChanged.connect(lambda text: model.filter_data(text, self.le_SearchName.text(), self.le_SearchIdent.text(), self.le_SearchAirport.text()))
self.le_SearchName.textChanged.connect(lambda text: model.filter_data(self.le_SearchCountry.text(), text, self.le_SearchIdent.text(), self.le_SearchAirport.text()))
self.le_SearchIdent.textChanged.connect(lambda text: model.filter_data(self.le_SearchCountry.text(), self.le_SearchName.text(), text, self.le_SearchAirport.text()))
self.le_SearchAirport.textChanged.connect(lambda text: model.filter_data(self.le_SearchCountry.text(), self.le_SearchName.text(), self.le_SearchIdent.text(), text))
self.pb_ResetSearches.clicked.connect(self.reset_searches)
self.tv_RP.clicked.connect(self.get_row_data)
def setup(self):
# connect to the database and create a cursor
conn = sqlite3.connect('data/VRPsS10.db')
c = conn.cursor()
# create a table VRPs
c.execute("""CREATE TABLE if not exists VRPs(
Country text,
Name text,
Ident text,
Airport text,
Source text,
Cycle text,
Elevation text,
Lat_DD text,
Lon_DD text,
Lat_DMS text,
Lon_DMS text)""")
# create a table Updates
c.execute("""CREATE TABLE if not exists Updates(
Effective text,
Cycle text)""")
# commit the changes and close connection
conn.commit()
conn.close()
def load_database(self):
# connect to the database and create a cursor
conn = sqlite3.connect('data/VRPsS10.db')
# read from the 'Updates' table
query = 'SELECT * FROM Updates'
self.df_update = pd.read_sql_query(query, conn)
self.setWindowTitle(f'AIRAC: {self.df_update.iat[0, 1]} Date: {self.df_update.iat[0, 0]}')
del [[self.df_update]]
# read from the 'VRPs' table
query = 'SELECT * FROM VRPs'
self.df = pd.read_sql_query(query, conn)
def initialise(self):
self.tv_RP.setColumnWidth(0, 60)
self.tv_RP.setColumnWidth(1, 230)
self.tv_RP.setColumnWidth(2, 60)
self.tv_RP.setColumnWidth(3, 105)
self.tv_RP.setColumnWidth(4, 60)
self.tv_RP.setColumnWidth(5, 60)
self.tv_RP.setColumnWidth(6, 70)
self.tv_RP.setColumnWidth(7, 80)
self.tv_RP.setColumnWidth(8, 80)
self.tv_RP.setColumnWidth(9, 110)
self.tv_RP.setColumnWidth(10, 110)
self.tv_RP.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft)
self.tv_RP.setAlternatingRowColors(True)
# load map
self.webView = QWebEngineView()
location = (50.81506933272997, -1.203825772101116)
self.display_map(location)
def reset_searches(self):
self.le_SearchCountry.setText("")
self.le_SearchName.setText("")
self.le_SearchIdent.setText("")
self.le_SearchAirport.setText("")
def get_row_data(self, item):
location = (float(self.df.iloc[item.row(), self.df.columns.get_loc("Lat_DD")]),
float(self.df.iloc[item.row(), self.df.columns.get_loc("Lon_DD")]))
# display the map with this location
self.display_map(location)
def display_map(self, location):
# delete current webview
self.webView.deleteLater()
# create a separate map dataframe
df_map = self.df.copy()
df_map['Popup'] = "Country: " + df_map['Country'] + "<br>" + \
"Name: " + df_map['Name'] + "<br>" + \
"Ident: " + df_map['Ident'] + "<br>" + \
"Elevation: " + df_map['Elevation'] + " feet" + "<br>" + \
"Position DD: " + df_map['Lat_DD'] + ", " + df_map['Lon_DD'] + "<br>" + \
"Position DMS: " + df_map['Lat_DMS'] + ", " + df_map['Lon_DMS']
# change columns to float
df_map['Lat_DD'] = df_map['Lat_DD'].astype(float)
df_map['Lon_DD'] = df_map['Lon_DD'].astype(float)
# set up icons and markers
vrp_map = folium.Map(location=location, zoom_start=12, control_scale=True)
vrp_map.add_child(GetLatLngPopup())
callback = ('function (row) {'
'var marker = L.marker(new L.LatLng(row[0], row[1]), {color: "red"});'
'var icon = L.AwesomeMarkers.icon({'
"icon: 'info-sign',"
"iconColor: 'white',"
"markerColor: 'blue',"
"prefix: 'glyphicon',"
"extraClasses: 'fa-rotate-0'"
'});'
'marker.setIcon(icon);'
"var popup = L.popup({maxWidth: '300'});"
"const display_text = {text: row[2]};"
"var my_text = $(`<div id='my_text' class='display_text' style='width: 100.0%; height: 100.0%;'> "
"${display_text.text}</div>`)[0];"
"popup.setContent(my_text);"
"marker.bindPopup(popup);"
'return marker};')
vrp_map.add_child(FastMarkerCluster(df_map[['Lat_DD', 'Lon_DD', 'Popup']].values.tolist(), callback=callback))
# display map
self.webView = QWebEngineView()
self.webView.setHtml(vrp_map.get_root().render())
self.vl_Map.addWidget(self.webView)
# destroy map dataframe
del [[df_map]]
def display_filtered_map(self):
print(self.filtered_df)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
我尝试了很多不同的方法来实现这一目标,但现在我完全困惑了,但没有一个方法能让我到达我想去的地方。
我很感激您能提供的任何帮助。提前致谢