让我们说我有一个包含三列的表:前两列的大小是未知的,如果有可用空间并且最后一列的大小已知且已修复,则应扩展。由于我已经是QTableView
和QTableModel
的子类,我认为子类化QHeaderView
可能是要走的路,这是MWE:
#!/usr/bin/env python
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class MyTableModel(QAbstractTableModel):
def __init__(self, parent: QObject=None):
super().__init__(parent)
self.entries = [
['row0, col0 (expanding)', 'row0, col1 (expanding)', 'row0, col2']
, ['row1, col0 (expanding)', 'row1, col1 (expanding)', 'row1, col2']
, ['row2, col0 (expanding)', 'row2, col1 (expanding)', 'row2, col2']
]
def headerData(
self
, section : int
, orientation: Qt.Orientation
, role : Qt.ItemDataRole=Qt.DisplayRole
):
if orientation == Qt.Vertical:
return QVariant()
if role == Qt.DisplayRole:
if section == 0:
return 'Expanding 0'
if section == 1:
return 'Expanding 1'
if section == 2:
return 'Fixed 0'
return 'Fix Your Columns'
def data(
self
, index: QModelIndex=QModelIndex()
, role : Qt.ItemDataRole=Qt.DisplayRole
):
if role != Qt.DisplayRole:
return QVariant()
return self.entries[index.row()][index.column()]
def rowCount(self, parent: QModelIndex=QModelIndex()):
return len(self.entries)
def columnCount(self, parent: QModelIndex=QModelIndex()):
return len(self.entries[0])
class MyTableView(QTableView):
def __init__(self, parent: QObject=None):
super().__init__(parent)
class MyHeaderView(QHeaderView):
def __init__(
self
, orientation: Qt.Orientation=Qt.Horizontal
, parent : QWidget=None
):
super().__init__(orientation, parent)
Stretch, Fixed = QHeaderView.Stretch, QHeaderView.Fixed
self.SECTION_RESIZE_MODES = [Stretch, Stretch, Fixed]
def column(self) -> int:
return 3
def setModel(self, model: QAbstractItemModel=None):
super().setModel(model)
# This loop is the only reason why I am overwriting setModel
# It adds column behaviour once the model is in place
for i, mode in enumerate(self.SECTION_RESIZE_MODES):
self.setSectionResizeMode(i, mode)
class MyCentralWidget(QWidget):
def __init__(self, parent: QObject=None):
super().__init__(parent)
self.my_table_model = MyTableModel(parent=parent)
self.my_table_view = MyTableView(parent=parent)
self.my_header_view = MyHeaderView(parent=parent)
self.my_table_view.setModel(self.my_table_model)
self.my_header_view.setModel(self.my_table_model)
self.my_table_view.setHorizontalHeader(self.my_header_view)
self.layout = QVBoxLayout(self)
self.layout.addWidget(self.my_table_view)
self.setLayout(self.layout)
class MyMainWindow(QMainWindow):
def __init__(self, parent: QObject=None):
super().__init__(parent)
self.central_widget = MyCentralWidget(self)
self.setCentralWidget(self.central_widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = MyMainWindow()
main_window.show()
sys.exit(app.exec())
最终,它做我想要的:桌子占据整个可用的水平空间,最后一列是固定宽度,前两个共享可用空间50/50。但是,此设置对于在.setModel
和MyTableView
上调用MyHeaderView
非常敏感:
MyCentralWidget
中的以下顺序会导致分段错误:
self.my_table_view = MyTableView(parent=parent)
self.my_header_view = MyHeaderView(parent=parent)
self.my_table_view.setHorizontalHeader(self.my_header_view)
self.my_table_view.setModel(self.my_table_model)
self.my_header_view.setModel(self.my_table_model)
因此,在将相同模型设置为两者之前,您无法在表视图上设置标题。此外,如果我将self.setSectionResizeMode(i, mode)
循环从setModel
移动到构造函数中,则会再次发生分段错误(可能是因为此时模型仍未设置)。
底线:这非常脆弱。使用复杂列逻辑创建表的更可靠/可靠的方法是什么?此外,我不希望在MyCentralWidget
中进行任何特定于视图的设置。在我看来,那个小部件应该创建/组合几个对象并将它们发送到布局......