如果Qt方法具有由用户在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_())

最佳答案

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

用户版本中放置在项目中的数据可以是任何类型,例如文本,这会产生错误,因为DataFrame仅接受数字值,因此我们必须提供可对此进行验证的输入QLineEditQDoubleValidator

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)


例:

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

    def initUI(self):
        self.setGeometry(700, 100, 350, 380)
        df_rows = 10
        df_cols = 3
        df = pd.DataFrame(np.random.randn(df_rows, df_cols))
        self.tableWidget = TableWidget(df, self)

        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)

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


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

07-26 09:29
查看更多