【问题标题】:PyQt5 - Updating DataFrame behind QTableWidgetPyQt5 - 更新 QTableWidget 后面的 DataFrame
【发布时间】:2018-04-11 18:31:22
【问题描述】:

如果用户在 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_())

【问题讨论】:

    标签: python pandas pyqt pyqt5 qtablewidget


    【解决方案1】:

    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_())
    

    【讨论】:

    • 谢谢你,cellChanged 真的把这个问题搞大了! :)
    • 很好,但是当我的数据帧索引不是0、1、2、3...时,它仍然将0、1、2、3...作为索引,如何使它成为实际数据框索引?
    猜你喜欢
    • 1970-01-01
    • 2017-02-04
    • 1970-01-01
    • 2020-08-06
    • 1970-01-01
    • 1970-01-01
    • 2019-01-12
    • 2020-08-17
    • 1970-01-01
    相关资源
    最近更新 更多