将 pandas DataFrame 与 PyQt5 QTableView 同步
Posted
技术标签:
【中文标题】将 pandas DataFrame 与 PyQt5 QTableView 同步【英文标题】:Synchronize pandas DataFrame with PyQt5 QTableView 【发布时间】:2020-07-09 10:06:31 【问题描述】:我有一个可编辑的 QTableView
,它从 pandas
DataFrame
读取值。
我正在寻找的是,当我更改一个单元格的值时,pandas
DataFrame
会自动同步。目的是继续使用更新后的DataFrame
进行操作,例如更新DataFrame
的其他行的值并刷新QTableView
。
我在论坛上看到有类似的问题,但是由于MVC
对我来说是新的并且我不是专业程序员,我发现解决方案很难理解并且我没有设法实现它们在我的代码中。
我在这里粘贴我目前的代码。
run.py
import pandas as pd
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableView
from cnt_init_values import CntInitialValues
from tablemodel_editable import PandasModel
class MainWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
# Packages.
# ---------
self.pd = pd
# Instancies of class.
# --------------------
self.cnt_init_val = CntInitialValues(self)
# Objects of the aplication.
# --------------------------
self.df_table = pd.DataFrame()
# PyQt5 objects.
# --------------
self.tableview = QTableView()
# Add initial values to QTableView and show them.
# -----------------------------------------------
self.df_table = self.cnt_init_val.dataframe_initial()
self.cnt_init_val.initial_values(self.df_table)
# PyQt5 outputs.
# ==============
def table_output(self, df):
print(self.df_table)
model = PandasModel(df)
self.tableview.setModel(model)
self.tableview.resize(350, 250)
self.tableview.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
myapp = MainWindow()
sys.exit(app.exec_())
cnt_init_values.py
from initialvalues import InitialValues
class CntInitialValues:
"""Controller"""
def __init__(self, window):
self.w = window
def dataframe_initial(self):
d_initial_values = InitialValues.d_INITIAL_VALUES
df_initial = self.w.pd.DataFrame(d_initial_values)
return df_initial
def initial_values(self, df):
self.w.table_output(df)
initialvalues.py
class InitialValues:
vals = [float(i) for i in range(6)]
d_INITIAL_VALUES =
'x': vals,
'x²': [val**2 for val in vals],
'x³': [val**3 for val in vals]
tablemodel_editable.py
from PyQt5.QtCore import QAbstractTableModel, Qt
class PandasModel(QAbstractTableModel):
def __init__(self, data):
QAbstractTableModel.__init__(self)
self._data = data
def rowCount(self, parent=None):
return self._data.shape[0]
def columnCount(self, parnet=None):
return self._data.shape[1]
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
if role == Qt.DisplayRole:
return str(self._data.iloc[index.row(), index.column()])
column_count = self.columnCount()
for column in range(0, column_count):
if (index.column() == column and role == Qt.TextAlignmentRole):
return Qt.AlignHCenter | Qt.AlignVCenter
return None
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self._data.columns[col]
return None
def setData(self, index, value, role):
if not index.isValid():
return False
if role != Qt.EditRole:
return False
row = index.row()
if row < 0 or row >= len(self._data.values):
return False
column = index.column()
if column < 0 or column >= self._data.columns.size:
return False
self._data.iloc[row][column] = value
self.dataChanged.emit(index, index)
return True
def flags(self, index):
flags = super(self.__class__,self).flags(index)
flags |= Qt.ItemIsEditable
flags |= Qt.ItemIsSelectable
flags |= Qt.ItemIsEnabled
flags |= Qt.ItemIsDragEnabled
flags |= Qt.ItemIsDropEnabled
return flags
【问题讨论】:
【参考方案1】:解决方案太简单了,我不明白。如果有人可以向我解释发生了什么。
我指出我在run.py
中所做的更改:
run.py 已编辑
class MainWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
uic.loadUi('table.ui', self) # --- Loading from Qt Designer. ---
# Packages.
# ---------
self.pd = pd
# Instancies of class.
# --------------------
self.cnt_init_val = CntInitialValues(self)
# Attributes of the instance.
# ---------------------------
self.df_table = pd.DataFrame()
self.model = '' # --- Instance variable for model. ---
# PyQt5 objects.
# --------------
self.tableview = self.tableView
self.btn_print_df = self.pushButtonPrintDataFrame # --- pushButton to print DataFrame. ---
# Add initial values to QTableView and show them.
# -----------------------------------------------
self.df_table = self.cnt_init_val.dataframe_initial()
self.cnt_init_val.initial_values(self.df_table)
# Events.
# -------
self.btn_print_df.clicked.connect(self.dataframe_output) # --- pushButton prints DataFrame. ---
# PyQt5 outputs.
# ==============
def table_output(self, df):
print('\nInitial DataFrame:')
print(self.df_table)
self.model = PandasModel(df)
self.tableview.setModel(self.model)
self.tableview.show()
# Terminal outputs. # --- DaraFrame output. ---
# =================
def dataframe_output(self):
print('\nUpdated DataFrame:')
print(self.df_table)
首先,当应用程序执行时:
Initial DataFrame:
x x² x³
0 0.0 0.0 0.0
1 1.0 1.0 1.0
2 2.0 4.0 8.0
3 3.0 9.0 27.0
4 4.0 16.0 64.0
5 5.0 25.0 125.0
更改表格中的一些值后:
Updated DataFrame:
x x² x³
0 999.0 0.0 0.0
1 1.0 1.0 1.0
2 2.0 4.0 8.0
3 3.0 9.0 27.0
4 4.0 16.0 64.0
5 5.0 25.0 1111.0
现在我必须使用 DataFrame 来使行的值保持一致,但这是另一个问题。
【讨论】:
以上是关于将 pandas DataFrame 与 PyQt5 QTableView 同步的主要内容,如果未能解决你的问题,请参考以下文章
2020-03-12 PYQT5界面使用QtableView展示Pandas.DataFrame
用PyQt5来即时显示pandas Dataframe的数据,附qdarkstyle黑夜主题样式(美美哒的黑夜主题)
将 Pandas Multiindexed DataFrame 与 Singleindexed Pandas DataFrame 合并
Pandas:如何将 MultiIndex DataFrame 与单个索引 DataFrame 连接,以及自定义排序