具有相对宽度、可拉伸列的 QTableWidget

QTableWidget with relative-width, stretchable columns

我正在尝试实现类似于以下的 pyqt5 table:

首先:我什至不确定 QTableWidget 是最合适的小部件,因为我对 Qt 没有太多经验。 QGridLayout 可能更合适。我首先尝试了它,但不知何故我不知道如何让它满足要求,任何建议将不胜感激。

table 要求是:

我现在的问题是setSectionResizeModeresizeSection的使用冲突。我可以有不同的列宽或可拉伸的 table 宽度,但我不知道如何同时实现。

示例代码如下所示:

from PyQt5.QtWidgets import QApplication, QWidget, QHeaderView, QTableWidget, QTableWidgetItem, QVBoxLayout
import sys

data = {'col1':['1','2','3','4'],
        'col2':['1','2','1','3'],
        'col3':['1','1','2','1']}


class MainWindow(QWidget):

    def __init__(self):

        super().__init__()

        self.table = QTableWidget()
        self.table.setRowCount(4)
        self.table.setColumnCount(3)
        self.table.verticalHeader().hide()
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # self.table.horizontalHeader().resizeSection(1, 200) <-- no effect if stretch is activated

        self.table.setHorizontalHeaderLabels([colName for colName in data])
        self.fillTable()

        self.layout = QVBoxLayout()
        self.layout.addWidget(self.table)
        self.setLayout(self.layout)


    def fillTable(self):
        for colNumber, colName in enumerate(data):
            for rowNumber, value in enumerate(data[colName]):
                self.table.setItem(rowNumber, colNumber, QTableWidgetItem(value))


if __name__=="__main__":

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

这是我的另一个尝试,使用 QGridLayout。这里的问题是当 window 调整大小时,列不会扩展。

import sys
from PyQt5.QtWidgets import (QWidget, QGridLayout, QLabel, QPushButton, QApplication, QScrollArea, QVBoxLayout)
from PyQt5.QtCore import Qt

class MainWindow(QWidget):

    def __init__(self):

        super().__init__()

        # Label
        self.label = QLabel('Test')

        # Grid
        self.grid = QWidget()
        self.gridLayout = QGridLayout()
        self.grid.setLayout(self.gridLayout)
        self.grid.setMinimumWidth(600) # Without this, the width relations are not kept

        # Grid elements
        for i in range(20):
            self.gridLayout.addWidget(QPushButton('A'), i, 0, 1, 1)
            self.gridLayout.addWidget(QPushButton('B'), i, 1, 1, 3)
            self.gridLayout.addWidget(QPushButton('C'), i, 4, 1, 1)

        # Scroll area
        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.grid)
        self.scrollArea.setMinimumWidth(self.grid.sizeHint().width())
        self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        # Window layout
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.label)
        self.layout.addWidget(self.scrollArea)
        self.setLayout(self.layout)


if __name__ == '__main__':

    app = QApplication(sys.argv)
    windowExample = MainWindow()
    windowExample.show()
    sys.exit(app.exec_())

使用网格布局可能是最佳选择,因为项目视图更适合显示项目模型而不包含 GUI 元素。

你缺少的是 widgetResizable 属性:

If this property is set to false (the default), the scroll area honors the size of its widget.

[...] If this property is set to true, the scroll area will automatically resize the widget in order to avoid scroll bars where they can be avoided, or to take advantage of extra space.

那么,您不应该使用列跨度来确保小部件自行扩展,而是 setColumnStretch

最后,为了保证滚动区始终显示没有"cutting"右侧的内容,不要禁用水平滚动条,而是根据内容适当设置最小宽度区域、垂直滚动条宽度和滚动区域框架宽度。

考虑到所有这些,您显然不再需要设置网格最小宽度。

    # Grid elements
    for i in range(20):
        self.gridLayout.addWidget(QPushButton('A'), i, 0)
        self.gridLayout.addWidget(QPushButton('B'), i, 1)
        self.gridLayout.addWidget(QPushButton('C'), i, 2)
    # ensure that the second column uses a stretch factor bigger than the
    # default 0 value (which will only honor the size hints and policies of
    # each widget
    self.gridLayout.setColumnStretch(1, 1)

    # Scroll area
    self.scrollArea = QScrollArea()
    self.scrollArea.setWidget(self.grid)
    self.scrollArea.setWidgetResizable(True)
    # compute the correct minimum width
    width = (self.grid.sizeHint().width() + 
        self.scrollArea.verticalScrollBar().sizeHint().width() + 
        self.scrollArea.frameWidth() * 2)
    self.scrollArea.setMinimumWidth(width)