PyQt5:QTableView中对列大小的细粒度控制

时间:2018-01-20 22:36:57

标签: python-3.x qt pyqt5

让我们说我有一个包含三列的表:前两列的大小是未知的,如果有可用空间并且最后一列的大小已知且已修复,则应扩展。由于我已经是QTableViewQTableModel的子类,我认为子类化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。但是,此设置对于在.setModelMyTableView上调用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中进行任何特定于视图的设置。在我看来,那个小部件应该创建/组合几个对象并将它们发送到布局......

0 个答案:

没有答案