PySide - PyQt:如何将QTableWidget列宽设置为可用空间的比例?

44
我正在使用PySide开发一款计算机应用程序,并且正在使用QTableWidget。假设我的表格有3列,但它们包含的数据非常不同,例如(对于每一行)第一列中有一个长句子,然后在最后两列中有三位数的数字。我想要调整表格大小以适应数据,或者至少能够将列大小设置为可用空间的70/15/15%
什么是最好的方法?
我尝试了在阅读this question之后使用table.horizontalHeader().setResizeMode(QHeaderView.Stretch),但它使得3个列的大小相同。
我也尝试了table.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents),感谢Fabio评论,但它不能像需要的那样填充所有可用空间。
QHeaderView文档中,InteractiveFixedStretchResizeToContents都无法给我所需的结果(见第二次编辑)。
任何帮助都将不胜感激,即使是关于Qt/C++的!非常感谢。

编辑:我找到了一种解决方法,但仍不是我想要的。

header = table.horizontalHeader()
header.setResizeMode(QHeaderView.ResizeToContents)
header.setStretchLastSection(True)

如果存在一个setStretchFirstSection方法,那将会更好,但不幸的是似乎没有这样的方法。


编辑2:

表格中唯一可修改的是最后一列,用户可以在其中输入数字。红色箭头表示我想要的内容。

StretchStretch时会发生以下情况:

ResizeToContents ResizeToContents时会发生以下情况:


尝试使用QHeaderView.ResizeToContents而不是QHeaderView.Stretch。 - Fabio
这个可以用,但不完全符合我的要求,因为使用 ResizeToContents 时,如果我的列不够大,它们就无法填满可用空间。我会进行编辑以使其更加清晰明了。 - AdrienW
对于您的第二次编辑,我认为正确的方法是设置列的默认宽度,根据您的粗略估计,然后由于可以拉伸,用户可以随后根据自己的需求进行修改。 - frankliuao
11个回答

98

这可以通过为每个列设置resize-mode来解决。第一节必须拉伸以占用可用空间,而最后两节只需调整大小以适应其内容:

PyQt5:

header = self.table.horizontalHeader()       
header.setSectionResizeMode(0, QHeaderView.Stretch)
header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
header.setSectionResizeMode(2, QHeaderView.ResizeToContents)

PyQt6/PyQt5:

header = self.table.horizontalHeader()       
header.setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch)
header.setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents)
header.setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents)

PyQt4:

header = self.table.horizontalHeader()
header.setResizeMode(0, QHeaderView.Stretch)
header.setResizeMode(1, QHeaderView.ResizeToContents)
header.setResizeMode(2, QHeaderView.ResizeToContents)

3
我不知道我可以为每一列选择不同的QHeaderView。尽管如此,我已经将最后两列更改为“Fixed”,然后使用self.table.setColumnWidth(index, width)添加了最小宽度(这样更适合我的情况)。 - AdrienW
6
在Qt5中,该函数已更改为setSectionResizeMode()。 - Ali Mirzaei

14

如前所述,您可以通过设置每个列的resize-mode来实现。但是,如果您有很多列,则代码量可能会很大。 我的做法是将“general” resize-mode设置为“ResizeToContent”,然后将一个(或多个)列设置为“Stretch”!

以下是代码:

PyQt4:

header = self.table.horizontalHeader()
header.setResizeMode(QtGui.QHeaderView.ResizeToContents)
header.setResizeMode(0, QtGui.QHeaderView.Stretch)

PyQt5:

header = self.table.horizontalHeader()
header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)       
header.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)

5

PyQt4

header = self.table.horizontalHeader()
header.setResizeMode(0, QtGui.QHeaderView.Stretch)
header.setResizeMode(1, QtGui.QHeaderView.ResizeToContents)
header.setResizeMode(2, QtGui.QHeaderView.ResizeToContents)
header.setResizeMode(3, QtGui.QHeaderView.Stretch)

PyQt5

header = self.table.horizontalHeader()       
header.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
header.setSectionResizeMode(3, QtWidgets.QHeaderView.Stretch)

4
我曾使用过 `setMinimumSectionSize`,它解决了我的 QTableView 单元格大小问题。
self.questionWidget.tableView.setModel(self.model)
self.questionWidget.tableView.verticalHeader().setVisible(False)
self.questionWidget.tableView.horizontalHeader().setMinimumSectionSize(200)


3
您可以使用 QItemDelegates 或者 QStyledItemDelegates 来实现此功能。如果您想要自动调整大小并具有自动拉伸功能,您需要选择哪一列是“拉伸”列。
class ResizeDelegate(QStyledItemDelegate):

    def __init__(self, table, stretch_column, *args, **kwargs):
        super(ResizeDelegate, self).__init__(*args, **kwargs)        
        self.table = table
        self.stretch_column = stretch_column

    def sizeHint(self, option, index):
        size = super(ResizeDelegate, self).sizeHint(option, index)
        if index.column() == self.stretch_column:
            total_width = self.table.viewport().size().width()
            calc_width = size.width()
            for i in range(self.table.columnCount()):
                if i != index.column():
                    option_ = QtGui.QStyleOptionViewItem()
                    index_ = self.table.model().index(index.row(), i)
                    self.initStyleOption(option_, index_)
                    size_ = self.sizeHint(option_, index_)
                    calc_width += size_.width()
            if calc_width < total_width:
                size.setWidth(size.width() + total_width - calc_width)
        return size

...

table = QTableWidget()
delegate = ResizeDelegate(table, 0)
table.setItemDelegate(delegate)
... # Add items to table
table.resizeColumnsToContents()

您可以将调整模式设置为ResizeToContents,或者如果您希望用户根据需要调整列宽,只需在更改表格项后手动调用resizeColumnsToContents即可。您还可能需要对宽度计算进行微调,因为列之间的边距和填充(例如为每个列添加一两个像素来考虑单元格边框的calculated_width)。

这很好,因为现在我的列不会像以前那样随时调整大小,但它们仍然没有占用所有可用的空间,而更改“stretch”列似乎没有任何效果...我做错了什么吗?我将编辑我的问题并附上我所得到的结果。 - AdrienW

2

我不得不移除QtWidget才能使我的工作正常。

        header = self.tag_table.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.ResizeToContents)

1
是否需要 QtWidget. 取决于您导入模块的方式 ;) - AdrienW

1

PyQt6

header = self.table.horizontalHeader()       
header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeMode.Stretch)
header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeMode.ResizeToContents)
header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeMode.ResizeToContents)

调整大小选项是类型为ResizeMode的枚举。
其他可用选项包括:

 Interactive = ... # type: QHeaderView.ResizeMode
 Fixed = ... # type: QHeaderView.ResizeMode
 Stretch = ... # type: QHeaderView.ResizeMode
 ResizeToContents = ... # type: QHeaderView.ResizeMode
 Custom = ... # type: QHeaderView.ResizeMode

0

这个方法在PyQt5中对我有效:

table_name.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)

它将自动调整所有列的大小。

以下是我所有的水平表头设置:

    table_name.horizontalHeader().setVisible(True)
    table_name.horizontalHeader().setCascadingSectionResizes(True)
    table_name.horizontalHeader().setDefaultSectionSize(140)
    table_name.horizontalHeader().setHighlightSections(False)
    table_name.horizontalHeader().setMinimumSectionSize(100)
    table_name.horizontalHeader().setSortIndicatorShown(False)
    table_name.horizontalHeader().setStretchLastSection(False)
   table_name.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)

0

在 PySide6 中修复之前,QTableView 中的 5 列会超出可见表格的范围

修复后,它们完美对齐(顺便提一下,表格视图的固定宽度为 371 像素)(也使用了 QtDesigner)

self.table_view = QTableView()
self.model.setHeaderData(index,Qt.Horizontal,value)
self.table_view.setColumnWidth(0,65)  #(index,width-px)
self.table_view.setColumnWidth(1,75)
self.table_view.setColumnWidth(2,75)
self.table_view.setColumnWidth(3,75)
self.table_view.setColumnWidth(4,71)

屏幕截图(绿色屏幕右下角): 在此输入图片描述


0
在一个继承自QTableWidget的类中,我用PyQt5实现了这个函数:
def set_header_stretch_first_section(self):
    header = self.horizontalHeader()
    header.setSectionResizeMode(0, QHeaderView.Stretch)
    for i in range(1, self.columnCount()):
        header.setSectionResizeMode(i, QHeaderView.ResizeToContents)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接