使用 QDataWidgetMapper 在 QTextEdit 中显示 Pandas 数据框

问题描述 投票:0回答:1

我有一个 pandas 数据框 (

df
),它使用
QTableView
显示在
TableModel
中。我还有
QTextEditor
,它应该使用
df
中使用的
TableModel
数据框进行一些数学运算,并且应该在
QTextEdit
中显示数据集名称(字符串变量)和修改后的数据框下方。为此,我创建了
QTextEditModel
。用户可以更改
QTableView
中的值,并且
QTextEdit
视图应相应更新。用户无法在
QTextEdit
中输入数据。由于
QTextEditModel
应该监视来自
dataChanged/layoutChanged
TableModel
信号,我在
TableModel
中初始化了
QTextEditModel
,对我来说,这看起来是安排此类监视的最简单方法(也许是错误的)。我设法让它部分工作。 我有几个问题:

  1. 我不知道如何使用
    QTextEdit
    QWidgetMapper
    中逐行显示pandas数据框。现在它在一行中显示所有数据。 当前显示: GUI of the software tool QTextEdit 中所需的输出:

Desired output in QTextEdit

  1. TextEditModel
    中,当我监视代码中
    TableModel
    中的以下行的数据变化时:

self.table1ViewModel.dataChanged.connect(lambda: self.setData(self.index_value, self.table1ViewModel.df.copy()))

我将信号连接到

setData
,我需要提供
QModelIndex
的值,但我不明白如何在这里获得
QModelIndex
值。在初始化模型期间,我通过将
QModelIndex
保存在
index_value
变量中做了一些作弊。

  1. 如何初始化
    self.df
    中的
    TextEditModel
    数据框,以便一旦
    TableModel
    中的数据框发生变化,它总是会更新?现在我正在用
    modify_data_frame
    方法制作数据帧的副本,这看起来不是正确的方法。

完整代码:

from PySide6.QtCore import QAbstractTableModel, Qt
from PySide6.QtWidgets import QWidget, QTableView, QTextEdit, QHBoxLayout, QApplication, QDataWidgetMapper
import pandas as pd
import sys
class TableModel(QAbstractTableModel):
    def __init__(self, df):
        super(TableModel, self).__init__()
        self.df = df

    def data(self, index, role):
        if index.isValid():
            row = index.row()
            col = index.column()
            if role == Qt.DisplayRole:
                value = self.df.iloc[row, col]
                return value

            elif role == Qt.EditRole:
                value = self.df.iloc[row, col]
                return value

    def setData(self, index, value, role=Qt.EditRole):
        if role == Qt.EditRole:
            row = index.row()
            col = index.column()
            self.df.iloc[row, col]=value
            self.dataChanged.emit(index, index)
            return True
        return False

    def flags(self, index):
        return Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable

    def rowCount(self, index):
        return self.df.shape[0]

    def columnCount(self, index):
        return self.df.shape[1]

class TextEditModel(QAbstractTableModel):
    def __init__(self, df):
        super(TextEditModel, self).__init__()
        self.table1ViewModel = TableModel(df)
        self.df = self.modify_data_frame(self.table1ViewModel.df)
        self.index_value = None
        self.table1ViewModel.dataChanged.connect(lambda: self.setData(self.index_value, self.modify_data_frame(self.table1ViewModel.df)))
        # self.table1ViewModel.layoutChanged.connect(lambda: self.setData(self.index_value, self.table1ViewModel.df.copy()))

    def data(self, index, role):
        if index.isValid():
            row = index.row()
            col = index.column()
            if role == Qt.EditRole:
                self.index_value = index
                name = "data set"
                value = name + '\n' + self.df.to_string()
                return value

    def setData(self, index, df, role=Qt.EditRole):
        if role == Qt.EditRole:
            print("!")
            print(type(df))
            name = "data set"
            # df["number"] = df["number"].astype(int) + 1
            # self.df = df.copy()
            # df["number"] = df["number"].astype(str)
            df = name + '\n' + df.to_string()
            print(df)
            print(type(df))
            self.dataChanged.emit(index, index)
            return True
        return False

    def flags(self, index):
        return Qt.ItemIsEnabled

    def rowCount(self, index):
        return self.df.shape[0]

    def columnCount(self, index):
        return self.df.shape[1]

    def modify_data_frame(self, df):
        print("!!!")
        self.df = df.copy()
        print(self.df)
        self.df["number"] = self.df["number"].astype(int) + 1
        self.df["number"] = self.df["number"].astype(str)
        return self.df

class MainWidget(QWidget):
    def __init__(self, parent=None):
        super(MainWidget, self).__init__(parent)

        df = pd.DataFrame({"name":["a", "b", "c"], "number": ["1", "2", "3"]})

        self.table1View = QTableView()
        self.textEdit = QTextEdit()

        layout = QHBoxLayout(self)
        layout.addWidget(self.table1View)
        layout.addWidget(self.textEdit)

        model = TextEditModel(df)
        # self.textEdit.setModel(model)
        self.table1View.setModel(model.table1ViewModel)

        self.mapper = QDataWidgetMapper(self)
        self.mapper.setModel(model)
        self.mapper.addMapping(self.textEdit, 0)
        self.mapper.toFirst()


app = QApplication(sys.argv)
mywindow = MainWidget()
mywindow.show()
sys.exit(app.exec())
python-3.x pyside6 qtextedit qabstracttablemodel qdatawidgetmapper
1个回答
0
投票

以防万一有人遇到同样的问题。我用这种方法解决了这个问题:

from PySide6.QtCore import QAbstractTableModel, Qt
from PySide6.QtWidgets import QWidget, QTableView, QTextEdit, QHBoxLayout, QApplication, QDataWidgetMapper
import pandas as pd
import sys
class TableModel(QAbstractTableModel):
    def __init__(self, df):
        super(TableModel, self).__init__()
        self.df = df

    def data(self, index, role):
        if index.isValid():
            row = index.row()
            col = index.column()
            if role == Qt.DisplayRole:
                value = self.df.iloc[row, col]
                return value

            elif role == Qt.EditRole:
                value = self.df.iloc[row, col]
                return value

    def setData(self, index, value, role=Qt.EditRole):
        if role == Qt.EditRole:
            row = index.row()
            col = index.column()
            self.df.iloc[row, col]=value
            self.dataChanged.emit(index, index)
            return True
        return False

    def flags(self, index):
        return Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable

    def rowCount(self, index):
        return self.df.shape[0]

    def columnCount(self, index):
        return self.df.shape[1]

class MainWidget(QWidget):
    def __init__(self, parent=None):
        super(MainWidget, self).__init__(parent)

        df = pd.DataFrame({"name":["a", "b", "c"], "number": ["1", "2", "3"]})

        self.table1View = QTableView()
        self.textEdit = QTextEdit()

        layout = QHBoxLayout(self)
        layout.addWidget(self.table1View)
        layout.addWidget(self.textEdit)

        model = TableModel(df)
        self.table1View.setModel(model)
        model.dataChanged.connect(lambda: self.display_data(self.modify_data_frame(model.df)))
        model.layoutChanged.connect(lambda: self.display_data(self.modify_data_frame(model.df)))
        self.display_data(self.modify_data_frame(model.df))

    def modify_data_frame(self, df):
        self.df = df.copy()
        self.df["number"] = self.df["number"].astype(int) + 1
        self.df["number"] = self.df["number"].astype(str)
        return self.df

    def display_data(self, df):
        self.textEdit.clear()
        self.textEdit.append(df.to_string())

app = QApplication(sys.argv)
mywindow = MainWidget()
mywindow.show()
sys.exit(app.exec())
© www.soinside.com 2019 - 2024. All rights reserved.