当数据源与 QSortFilterProxyModel 之间发生变化时,动态更新 QTableView

Updating QTableView on the fly when data source changes with a QSortFilterProxyModel in between

我正在尝试在数据源 (Pandas Dataframe) 更改时更新 QTableView。 我使用 QAbstractTableModel 作为“基础”table 模型和 QSortFilterProxyModel 进行一些过滤。

有时在运行时数据源会发生变化。据此,我的目标是重置“基础”table 模型 -> 通知代理模型 -> 更新 QTableView。

我尝试了以下代码,但这并没有在主窗口 class.

中调用 on_event() 后更改 TableView

下面是执行table代码...

import sys

import pandas as pd
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtCore import Qt

class DataStore(object):
    def __init__(self):

        data = {'Name':  ['name1', 'name2',"name3"],
        'Value': ['value1', 'value2',"value3"],
            'Setting': ["TRUE", "TRUE","FALSE"]
        }

        df = pd.DataFrame (data, columns = ['Name','Value','Setting'])

        self.df = df
    
        self.model = TableModel(self.df)
        self.proxy_model = ProxyModel(self.model)
        self.proxy_model.setSourceModel(self.model)
        self.proxy_model.setDynamicSortFilter(True)




class ProxyModel(QtCore.QSortFilterProxyModel):
    def __init__(self, parent):
        QtCore.QSortFilterProxyModel.__init__(self, parent)

    # Random filtering
    def filterAcceptsRow(self, sourceRow, sourceParent):
        print("Entered filterAcceptsRow function with source row: {}".format(sourceRow))
        idx = self.sourceModel().index(sourceRow, 2, sourceParent)
        value = idx.data()
        if value == "TRUE":
            return True
        if value == "FALSE":
            return False
    

class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        self.__data = data

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

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

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

    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                return str(self.__data.columns[section])

            if orientation == Qt.Vertical:
                return str(self.__data.index[section])




class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.ds = DataStore()
        self.table = QtWidgets.QTableView()       
        self.table.setModel(self.ds.proxy_model)
        self.on_event()
        self.setCentralWidget(self.table)
        self.setGeometry(600, 100, 400, 200)

    def on_event(self):
        data = {'Name':  ['new_name1', 'new_name2',"new_name3"],
        'Value': ['new_value1', 'new_value2',"new_value3"],
        'Description': ['new_descr1', 'new_descr2',"new_descr3"],
            'Setting': ["TRUE", "FALSE","TRUE"]
        }

        new_df = pd.DataFrame (data, columns = ['Name','Value','Setting'])
        self.ds.model.beginResetModel()
        self.ds.df = new_df
        self.ds.model.endResetModel()

app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

问题不在于 QSortFilterProxyModel,而是 sourceModel 中的信息未更新,您正在将 df 复制到 DataStore 但更新 TableModel 信息导致该错误。

import sys

import pandas as pd
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtCore import Qt


class DataStore(object):
    def __init__(self):

        data = {
            "Name": ["name1", "name2", "name3"],
            "Value": ["value1", "value2", "value3"],
            "Setting": ["TRUE", "TRUE", "FALSE"],
        }

        df = pd.DataFrame(data, columns=["Name", "Value", "Setting"])
        self.model = TableModel(df)
        self.proxy_model = ProxyModel()
        self.proxy_model.setSourceModel(self.model)
        self.proxy_model.setDynamicSortFilter(True)

    @property
    def df(self):
        return self.model.df

    @df.setter
    def df(self, df):
        self.model.df = df


class ProxyModel(QtCore.QSortFilterProxyModel):
    def filterAcceptsRow(self, sourceRow, sourceParent):
        print("Entered filterAcceptsRow function with source row: {}".format(sourceRow))
        idx = self.sourceModel().index(sourceRow, 2, sourceParent)
        value = idx.data()
        if value == "TRUE":
            return True
        if value == "FALSE":
            return False


class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        self.__data = data

    @property
    def df(self):
        return self.__data

    @df.setter
    def df(self, df):
        self.beginResetModel()
        self.__data = df.copy()
        self.endResetModel()

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

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

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

    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                return str(self.__data.columns[section])

            if orientation == Qt.Vertical:
                return str(self.__data.index[section])


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.ds = DataStore()
        self.table = QtWidgets.QTableView()
        self.table.setModel(self.ds.proxy_model)
        self.on_event()
        self.setCentralWidget(self.table)
        self.setGeometry(600, 100, 400, 200)

    def on_event(self):
        data = {
            "Name": ["new_name1", "new_name2", "new_name3"],
            "Value": ["new_value1", "new_value2", "new_value3"],
            "Description": ["new_descr1", "new_descr2", "new_descr3"],
            "Setting": ["TRUE", "FALSE", "TRUE"],
        }

        new_df = pd.DataFrame(data, columns=["Name", "Value", "Setting"])
        self.ds.df = new_df


app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()