PyQt5 中如何让 QTableWidget 的所有单元格随窗口缩放并保持可见?
可以为水平和垂直表头设置 QHeaderView.Stretch,再通过 setMinimumSectionSize() 降低列宽和行高的最小限制。使用 Qt.ScrollBarAlwaysOff 隐藏滚动条。
这样行列可以随表格的可用空间自动调整。窗口过小或行列过多时,无法同时保证所有单元格可见、文字完整且清晰可读。
为什么原来的设置没有达到预期?
原代码只设置了水平表头:
self.horizontalHeader().setSectionResizeMode(i, QHeaderView.Stretch)
这会让设置过的列宽随可用宽度调整,但行高不会随可用高度调整。要显示全部行,还需要设置垂直表头。
QHeaderView 的 minimumSectionSize 属性限制每个 section 的最小尺寸:水平表头限制列宽,垂直表头限制行高。默认限制可能与字体和样式有关。
你观察到的 58 可以先从这个属性排查,但不能据此认定所有环境的最小列宽都是 58:
print(self.horizontalHeader().minimumSectionSize())
print(self.verticalHeader().minimumSectionSize())
将调整模式改为 QHeaderView.Fixed 不会自动解除最小尺寸限制。Stretch 模式会自动分配尺寸,也不适合同时用 setColumnWidth() 手动控制列宽。
同时设置行列伸缩和最小尺寸
下面的 PyQt5 示例保留原来的窗口布局方式,展示尺寸适配设置:
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QHeaderView,
QHBoxLayout,
QMainWindow,
QTableWidget,
QWidget,
)
class ProductsTable(QTableWidget):
def __init__(self, table_rows, table_columns):
super().__init__()
self.setRowCount(table_rows)
self.setColumnCount(table_columns)
horizontal_header = self.horizontalHeader()
vertical_header = self.verticalHeader()
# 允许列宽和行高缩小到 1 像素。
horizontal_header.setMinimumSectionSize(1)
vertical_header.setMinimumSectionSize(1)
# 分别根据可用宽度和高度自动分配尺寸。
horizontal_header.setSectionResizeMode(QHeaderView.Stretch)
vertical_header.setSectionResizeMode(QHeaderView.Stretch)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
class MainWindow(QMainWindow):
def __init__(self, table_rows, table_columns):
super().__init__()
self.setWindowTitle("My App")
table = ProductsTable(table_rows, table_columns)
layout = QHBoxLayout()
layout.addWidget(table)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
这里的 1 表示允许的最小尺寸,并不会直接把所有单元格设成 1 像素。Stretch 会根据表格的可用空间分配实际尺寸,窗口大小变化时也会重新调整,通常不需要重写 resizeEvent()。
原来着色、拖放等与尺寸无关的逻辑可以继续保留。
为什么使用滚动条策略?
原代码通过以下方式隐藏滚动条:
self.verticalScrollBar().setVisible(False)
self.horizontalScrollBar().setVisible(False)
对于 QTableWidget,用滚动条策略表达“始终不显示”更合适:
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
隐藏滚动条不会压缩单元格。行高和列宽的调整仍依赖两个表头的 Stretch 模式和最小尺寸设置;空间不足时,只隐藏滚动条仍可能导致内容被裁切。
全部可见有哪些限制?
单元格显示在 table.viewport() 中,它的尺寸不包含表头和边框。可以在窗口显示后检查:
print(table.viewport().width(), table.viewport().height())
假设有 C 列、R 行,最小列宽为 w_min、最小行高为 h_min,至少需要满足:
viewport_width >= C * w_min
viewport_height >= R * h_min
即使满足这些条件,极小的单元格也可能只剩网格线,文字无法完整显示。如果主要用途是查看颜色分布,可以考虑隐藏表头或关闭网格,给概览留出更多空间:
self.horizontalHeader().hide()
self.verticalHeader().hide()
self.setShowGrid(False)
这些设置可以按需选用。如果必须看清每个单元格中的文字,就需要保留合理的最小尺寸,并在空间不足时允许滚动,或者限制窗口继续缩小。
备注:内容仅供参考。
