Python 如何使用QListView选择在QTableView中显示哪些列

Python 如何使用QListView选择在QTableView中显示哪些列,python,pyqt,pyqt5,Python,Pyqt,Pyqt5,假设我有以下数据帧: df = {'Banana': {0: 1, 1: 2, 2: 5}, 'Apple': {0: 3, 1: 4, 2: 3}, 'Elderberry': {0: 5, 1: 4, 2: 1}, 'Clementine': {0: 4, 1: 7, 2: 0}, 'Fig': {0: 1, 1: 9, 2: 3}} 它被传递到QAbstractTableModel并与QTableView一起显示: 现在,我想使用QListView创建一个单独的窗口,以显示df列名列表,

假设我有以下数据帧:

df = {'Banana': {0: 1, 1: 2, 2: 5}, 'Apple': {0: 3, 1: 4, 2: 3}, 'Elderberry': {0: 5, 1: 4, 2: 1},
'Clementine': {0: 4, 1: 7, 2: 0}, 'Fig': {0: 1, 1: 9, 2: 3}}
它被传递到QAbstractTableModel并与QTableView一起显示:

现在,我想使用QListView创建一个单独的窗口,以显示df列名列表,允许我指定要在上述QTableView中显示的列:

如果取消选中QListView中的列,则希望该列从QTableView中删除。类似地,如果我选中一列,该列应该添加到表视图中。列表视图的目的基本上是允许用户指定哪些列应该出现在表中

这样做的最佳方式是什么?我想我可以创建一个QListWidget并使用信号来更新QTableView。然而我有点不愿意这样做,因为我想它可能会变得非常混乱


因此,最佳做法是使用QListView,以便两个小部件都引用相同的数据模型,并自动执行吗?

您必须使用代理模型为listview构建模型,以转换原始模型,将标题映射到单个行或列,并添加复选框和另一个要筛选的复选框:

导入系统 从PyQt5导入QtCore、QtGui、QtWidgets 作为pd进口熊猫 类TableModelQtCore.QAbstractTableModel: def u_init__self,数据,父项=无: superTableModel,self.\u init\u父 self.\u data=数据 def rowCountself,索引: 返回self.\u data.shape[0] def columnCountself,索引: 返回self.\u数据.shape[1] def headerDataself、部门、方向、角色: 如果角色==QtCore.Qt.DisplayRole: 如果方向==QtCore.Qt.Horizontal: 返回strself.\u数据列[节] 如果方向==QtCore.Qt.Vertical: 返回strself.\u数据索引[部分] def dataself、索引、角色: row=index.row column=index.column value=self.\u data.iloc[行,列] 如果角色==QtCore.Qt.DisplayRole: 返回标准值 类CustomProxyQtCore.QSortFilterProxyModel: def u_init__self,父项=无: 超级。初始父级 self.show_columns=set def显示栏自身,c: self.show_columns.addc 自动失效过滤器 def hide_columnself,c: 如果c不在self.show_列中: 回来 self.show\u columns.removec 自动失效过滤器 def filterAcceptsColumnself,源\列,源\父项: 返回self.show\u列中的source\u列 类标题ProxyModelQTCore.QIdentityProxyModel: 选中=QtCore.pyqtSignalint,bool def u_init__self,父项=无: 超级。初始父级 self.checks={} def columnCountself,index=QtCore.QModelIndex: 返回1 def dataself,index,role=QtCore.Qt.DisplayRole: 如果角色==QtCore.Qt.DisplayRole: 返回self.headerDataindex.row、QtCore.Qt.Vertical、role elif角色==QtCore.Qt.CheckStateRole和index.column==0: 返回self.checks.get QtCore.QPersistentModelIndexindex,QtCore.Qt.Unchecked def setDataself,索引,值,角色=QtCore.Qt.EditRole: 如果index.isValid无效: 返回错误 如果角色==QtCore.Qt.CheckStateRole: self.checks[QtCore.QPersistentModelIndexindex]=值 self.checked.emitindex.row,布尔值 返回真值 返回错误 def标志自身,索引: fl=super.flagsindex 如果index.column==0: fl |=QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsUserCheckable 返回fl 类MainWindowQtWidgets.QMainWindow: 定义初始自我,型号: 超级__ self.model=model self.listview=qtwidts.QListView Transpose=QtCore.QTransposeProxyModel transpose.setSourceModelself.model header_模型=HeaderProxy模型 header_model.setSourceModeltranpose self.listview.setModelheader\u模型 self.tableview=qtwidts.QTableView self.filter\u proxy=CustomProxy self.filter_proxy.setSourceModelself.model self.tableview.setModelself.filter\u代理 标题\u model.checked.connectself.on\u checked central_widget=qtwidts.QWidget hlay=QtWidgets.QHBoxLayoutcentral\u小部件 hlay.addWidgetself.listview hlay.addWidgetself.tableview,拉伸=1 self.setCentralWidgetcentral\u小部件 def on_checkedself,r,状态: 如果说明: self.filter\u proxy.show\u columner 其他: self.filter\u proxy.hide\u columner 如果uuuu name uuuuu==\uuuuuuuu main\uuuuuuuu: app=qtwidts.QApplicationsys.argv df=pd.DataFrame { 香蕉:{0:1,1:2,2:5}, 苹果:{0:3,1:4,2:3}, 接骨木:{0:5,1:4,2:1}, 克莱门廷:{0:4,1:7,2:0}, 图:{0:1,1:9,2:3}, } 数据模型=表格模型 窗口1= MainWindowdata\u模型 window1.resize800400 window1.show sys.exitapp.exec_
您必须使用代理模型为listview创建模型以转换原始模型,将标题映射到单个行或列,并添加复选框和另一个要筛选的复选框:

导入系统 从PyQt5导入QtCore、QtGui、QtWidgets 作为pd进口熊猫 类TableModelQtCore.QAbstractTableModel: def u_init__self,数据,父项=无: superTableModel,self.\u init\u父 self.\u data=数据 def rowCountself,索引: 返回self.\u data.shape[0] def columnCountself,索引: 返回self.\u数据.shape[1] def headerDataself、部门、方向、角色: 如果角色==QtCore.Qt.DisplayRole: 如果方向==QtCore.Qt.Horizontal: 返回strself.\u数据列[节] 如果方向==QtCore.Qt.Vertical: 返回strself.\u数据索引[部分] def dataself、索引、角色: row=index.row column=index.column value=self.\u data.iloc[行,列] 如果角色==QtCore.Qt.DisplayRole: 返回标准值 类CustomProxyQtCore.QSortFilterProxyModel: def u_init__self,父项=无: 超级。初始父级 self.show_columns=set def显示栏自身,c: self.show_columns.addc 自动失效过滤器 def hide_columnself,c: 如果c不在self.show_列中: 回来 self.show\u columns.removec 自动失效过滤器 def filterAcceptsColumnself,源\列,源\父项: 返回self.show\u列中的source\u列 类标题ProxyModelQTCore.QIdentityProxyModel: 选中=QtCore.pyqtSignalint,bool def u_init__self,父项=无: 超级。初始父级 self.checks={} def columnCountself,index=QtCore.QModelIndex: 返回1 def dataself,index,role=QtCore.Qt.DisplayRole: 如果角色==QtCore.Qt.DisplayRole: 返回self.headerDataindex.row、QtCore.Qt.Vertical、role elif角色==QtCore.Qt.CheckStateRole和index.column==0: 返回self.checks.get QtCore.QPersistentModelIndexindex,QtCore.Qt.Unchecked def setDataself,索引,值,角色=QtCore.Qt.EditRole: 如果index.isValid无效: 返回错误 如果角色==QtCore.Qt.CheckStateRole: self.checks[QtCore.QPersistentModelIndexindex]=值 self.checked.emitindex.row,布尔值 返回真值 返回错误 def标志自身,索引: fl=super.flagsindex 如果index.column==0: fl |=QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsUserCheckable 返回fl 类MainWindowQtWidgets.QMainWindow: 定义初始自我,型号: 超级__ self.model=model self.listview=qtwidts.QListView Transpose=QtCore.QTransposeProxyModel transpose.setSourceModelself.model header_模型=HeaderProxy模型 header_model.setSourceModeltranpose self.listview.setModelheader\u模型 self.tableview=qtwidts.QTableView self.filter\u proxy=CustomProxy self.filter_proxy.setSourceModelself.model self.tableview.setModelself.filter\u代理 标题\u model.checked.connectself.on\u checked central_widget=qtwidts.QWidget hlay=QtWidgets.QHBoxLayoutcentral\u小部件 hlay.addWidgetself.listview hlay.addWidgetself.tableview,拉伸=1 self.setCentralWidgetcentral\u小部件 def on_checkedself,r,状态: 如果说明: self.filter\u proxy.show\u columner 其他: self.filter\u proxy.hide\u columner 如果uuuu name uuuuu==\uuuuuuuu main\uuuuuuuu: app=qtwidts.QApplicationsys.argv df=pd.DataFrame { 香蕉:{0:1,1:2,2:5}, 苹果:{0:3,1:4,2:3}, 接骨木:{0:5,1:4,2:1}, 克莱门廷:{0:4,1:7,2:0}, 图:{0:1,1:9,2:3}, } 数据模型=表格模型 window1=MainWindowdata\u模型 window1.resize800400 window1.show sys.exitapp.exec_
如果我理解正确,代理模型位于模型和视图之间,如下所示:数据->模型->代理->视图,允许在不实际更改模型的情况下为视图配置模型。这是正确的吗?您的代码是有意义的,但是当复选框被选中或取消选中时,我无法了解发生了什么。如果添加了一列,整个表视图是否会刷新,或者模型视图是否只绘制附加列?另外,我在代码中的什么地方可以设置复选框的默认状态?当前,复选框都未选中为默认状态?我向您发送了一封电子邮件email@Alan好的,我会查看它,几个小时后我会回复。如果我理解正确,代理模型位于模型和视图之间,如下所示:数据->模型->代理->视图,允许为视图w配置模型
没有实际改变模型。这是正确的吗?您的代码是有意义的,但是当复选框被选中或取消选中时,我无法了解发生了什么。如果添加了一列,整个表视图是否会刷新,或者模型视图是否只绘制附加列?另外,我在代码中的什么地方可以设置复选框的默认状态?当前,复选框都未选中为默认状态?我向您发送了一封电子邮件email@Alan好的,我会复习一下,几个小时后回复。
   Banana  Apple  Elderberry  Clementine  Fig
0       1      3           5           4    1
1       2      4           4           7    9
2       5      3           1           0    3
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.Qt import Qt
import pandas as pd


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, model):
        super().__init__()
        self.model = model
        self.table = QtWidgets.QTableView()
        self.table.setModel(self.model)
        self.setCentralWidget(self.table)


class TableModel(QtCore.QAbstractTableModel):

    def __init__(self, data):
        super(TableModel, self).__init__()
        self._data = data

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

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

    def headerData(self, section, orientation, role):
        # section is the index of the column/row.
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                return str(self._data.columns[section])

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

    def data(self, index, role):

        row = index.row()
        column = index.column()
        column_name = self._data.columns[column]
        value = self._data.iloc[row, column]

        if role == Qt.DisplayRole:
            print(str(value))
            return str(value)


app = QtWidgets.QApplication(sys.argv)
df = {'Banana': {0: 1, 1: 2, 2: 5}, 'Apple': {0: 3, 1: 4, 2: 3}, 'Elderberry': {0: 5, 1: 4, 2: 1}, 'Clementine': {0: 4, 1: 7, 2: 0}, 'Fig': {0: 1, 1: 9, 2: 3}}
data_model = TableModel(df)
window1 = MainWindow(data_model)
window1.resize(800, 400)
window1.show()
sys.exit(app.exec_())