如何使用QListView选择要在QTableView中显示的列

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

假设我有以下数据框:

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}}
   Banana  Apple  Elderberry  Clementine  Fig
0       1      3           5           4    1
1       2      4           4           7    9
2       5      3           1           0    3

传递给QAbstractTableModel并显示为QTableView

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

enter image description here

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

enter image description here

如果取消选中QListView中的一列,我希望将该列从QTableView中删除。同样,如果我检查一列,则应将该列添加到表视图中。列表视图的目的实质上是允许用户指定哪些列应出现在表中。

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

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

python pyqt pyqt5
1个回答
0
投票

您必须使用代理模型来构建列表视图的模型(转置原始模型,将标题映射到单个行或列,并添加复选框),另一个用于过滤:

talk to each other like this

import sys from PyQt5 import QtCore, QtGui, QtWidgets import pandas as pd class TableModel(QtCore.QAbstractTableModel): def __init__(self, data, parent=None): super(TableModel, self).__init__(parent) 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): if role == QtCore.Qt.DisplayRole: if orientation == QtCore.Qt.Horizontal: return str(self._data.columns[section]) if orientation == QtCore.Qt.Vertical: return str(self._data.index[section]) def data(self, index, role): row = index.row() column = index.column() value = self._data.iloc[row, column] if role == QtCore.Qt.DisplayRole: return str(value) class CustomProxy(QtCore.QSortFilterProxyModel): def __init__(self, parent=None): super().__init__(parent) self.show_columns = set() def show_column(self, c): self.show_columns.add(c) self.invalidateFilter() def hide_column(self, c): if c not in self.show_columns: return self.show_columns.remove(c) self.invalidateFilter() def filterAcceptsColumn(self, source_column, source_parent): return source_column in self.show_columns class HeaderProxyModel(QtCore.QIdentityProxyModel): checked = QtCore.pyqtSignal(int, bool) def __init__(self, parent=None): super().__init__(parent) self.checks = {} def columnCount(self, index=QtCore.QModelIndex()): return 1 def data(self, index, role=QtCore.Qt.DisplayRole): if role == QtCore.Qt.DisplayRole: return self.headerData(index.row(), QtCore.Qt.Vertical, role) elif role == QtCore.Qt.CheckStateRole and index.column() == 0: return self.checks.get( QtCore.QPersistentModelIndex(index), QtCore.Qt.Unchecked ) def setData(self, index, value, role=QtCore.Qt.EditRole): if not index.isValid(): return False if role == QtCore.Qt.CheckStateRole: self.checks[QtCore.QPersistentModelIndex(index)] = value self.checked.emit(index.row(), bool(value)) return True return False def flags(self, index): fl = super().flags(index) if index.column() == 0: fl |= QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsUserCheckable return fl class MainWindow(QtWidgets.QMainWindow): def __init__(self, model): super().__init__() self.model = model self.listview = QtWidgets.QListView() tranpose = QtCore.QTransposeProxyModel() tranpose.setSourceModel(self.model) header_model = HeaderProxyModel() header_model.setSourceModel(tranpose) self.listview.setModel(header_model) self.tableview = QtWidgets.QTableView() self.filter_proxy = CustomProxy() self.filter_proxy.setSourceModel(self.model) self.tableview.setModel(self.filter_proxy) header_model.checked.connect(self.on_checked) central_widget = QtWidgets.QWidget() hlay = QtWidgets.QHBoxLayout(central_widget) hlay.addWidget(self.listview) hlay.addWidget(self.tableview, stretch=1) self.setCentralWidget(central_widget) def on_checked(self, r, state): if state: self.filter_proxy.show_column(r) else: self.filter_proxy.hide_column(r) if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) df = pd.DataFrame( { "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_())

© www.soinside.com 2019 - 2024. All rights reserved.