我想使用pandas.DataFrame
将QTableView
内容显示为表格。我有一个子类QAbstractTableModel
的视图模型。这很好。
当用户更新DataFrame
内容时,我遇到问题(应用程序允许用户编写脚本,用户可以直接访问DataFrame
并更新它)。我想在GUI中显示更新的值。我可以通过发出dataChanged
信号来做到这一点。但是有很多方法来更新DataFrame
,我想知道为什么不让GUI始终显示DataFrame
的内容。
有没有切换这样做?或任何其他小部件?
我可以注册一个QTimer并每1秒发出一次dataChanged
- 有没有更好的方法来做到这一点。
我认为Android中的等效模型视图类与我的想法类似。
这是一个最小的代码。在这里按下按钮更新数据模型,
但视图将继续显示缓存的值。如果我在更新后发出数据更改信号,它将显示更新的值。但我希望尽可能避免这种情况,并希望视图始终显示来自DataFrame
:
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QTableView
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QWidget
import pandas as pd
from PyQt5.QtCore import QAbstractTableModel
from PyQt5.QtCore import Qt
class DFTableModel(QAbstractTableModel):
def __init__(self, df):
super().__init__()
self.df = df
def rowCount(self, parent):
return len(self.df)
def columnCount(self, parent):
return self.df.columns.size + 1
def data(self, index, role):
if index.isValid():
if role == Qt.DisplayRole:
if index.column() == 0:
return self.df.index[index.row()]
return str(self.df.values[index.row()][index.column() - 1])
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
if col == 0:
return 'index'
return self.df.columns[col - 1]
return None
def setData(self, index, value, role=Qt.EditRole):
k = self.df.columns[index.column() - 1]
self.df.set_value(index.row(), k, value)
return True
def flags(self, index):
if index.column() > 0:
return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
return Qt.ItemIsEnabled | Qt.ItemIsSelectable
def main():
app = QApplication([])
table_view = QTableView()
df = pd.DataFrame({'a': [1, 2, 3]})
model = DFTableModel(df)
table_view.setModel(model)
table_view.show()
def on_button_click():
print("Updated data")
df.set_value(0, 'a', 33)
button = QPushButton('Update data')
button.clicked.connect(on_button_click)
vbox = QVBoxLayout()
vbox.addWidget(table_view)
vbox.addWidget(button)
main = QWidget()
main.setLayout(vbox)
main.show()
app.exec()
if __name__ == '__main__':
main()