PyQt5 - 更新QTableWidget后面的DataFrame

时间:2017-10-30 17:26:19

标签: python pandas pyqt pyqt5 qtablewidget

如果用户在GUI中修改了特定元素,我在使用Qt方法更新DataFrame时遇到问题。

例如,当我运行以下代码时,我会得到一个10 x 3的DataFrame,并显示随机值。如果我尝试将任何单元格更改为值400,我双击,键入400,然后按Enter键。当我打印DataFrame时,该值仍然是旧值。我希望DataFrame单元更新用户更改值。

非常感谢!

import sys
import numpy as np
import pandas as pd
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon, QColor
from PyQt5.QtCore import pyqtSlot, Qt, QTimer

class App(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(700, 100, 350, 380)
        self.createTable()
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.tableWidget)
        self.button = QPushButton('Print DataFrame', self)
        self.layout.addWidget(self.button)
        self.setLayout(self.layout)
        self.button.clicked.connect(self.print_my_df)
        self.tableWidget.doubleClicked.connect(self.on_click_table)
        self.show()

    def createTable(self):
        self.tableWidget = QTableWidget()
        self.df_rows = 10
        self.df_cols = 3
        self.df = pd.DataFrame(np.random.randn(self.df_rows, self.df_cols))
        self.tableWidget.setRowCount(self.df_rows)
        self.tableWidget.setColumnCount(self.df_cols)
        for i in range(self.df_rows):
            for j in range(self.df_cols):
                x = '{:.3f}'.format(self.df.iloc[i, j])
                self.tableWidget.setItem(i, j, QTableWidgetItem(x))

    @pyqtSlot()
    def print_my_df(self):
        print(self.df)

    @pyqtSlot()
    def on_click_table(self):
        for currentQTableWidgetItem in self.tableWidget.selectedItems():
            print((currentQTableWidgetItem.row(), currentQTableWidgetItem.column()))
            self.print_my_df()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

1 个答案:

答案 0 :(得分:2)

QTableWidget不知道DataFrame的存在,因此它不会更新它。我们必须为此更新它,我们使用cellChanged信号为我们提供行和列,然后我们使用item()方法返回给定列和行的QTableWidgetItem,然后我们使用text()的{​​{1}}方法。

放置在用户版本的项目中的数据可以是任何类型,例如文本,这会产生错误,因为QTableWidgetItem只接受数值,我们必须提供验证的输入为此,我们将DataFrameQLineEdit放在一起。

QDoubleValidator

示例:

class FloatDelegate(QItemDelegate):
    def __init__(self, parent=None):
        QItemDelegate.__init__(self, parent=parent)

    def createEditor(self, parent, option, index):
        editor = QLineEdit(parent)
        editor.setValidator(QDoubleValidator())
        return editor


class TableWidget(QTableWidget):
    def __init__(self, df, parent=None):
        QTableWidget.__init__(self, parent)
        self.df = df
        nRows = len(self.df.index)
        nColumns = len(self.df.columns)
        self.setRowCount(nRows)
        self.setColumnCount(nColumns)
        self.setItemDelegate(FloatDelegate())

        for i in range(self.rowCount()):
            for j in range(self.columnCount()):
                x = '{:.3f}'.format(self.df.iloc[i, j])
                self.setItem(i, j, QTableWidgetItem(x))

        self.cellChanged.connect(self.onCellChanged)

    @pyqtSlot(int, int)
    def onCellChanged(self, row, column):
        text = self.item(row, column).text()
        number = float(text)
        self.df.set_value(row, column, number)