具有相对宽度、可拉伸列的 QTableWidget
QTableWidget with relative-width, stretchable columns
我正在尝试实现类似于以下的 pyqt5 table:
首先:我什至不确定 QTableWidget 是最合适的小部件,因为我对 Qt 没有太多经验。 QGridLayout 可能更合适。我首先尝试了它,但不知何故我不知道如何让它满足要求,任何建议将不胜感激。
table 要求是:
- 一些单元格包含文本,一些 QCheckBoxes 和一些 QRadioButtons
- table 宽度在调整大小时必须始终填充其父级宽度的 100%(我目前正在使用
setSectionResizeMode(QHeaderView.Stretch)
)
- table 应该可以垂直滚动
- 它的某些列具有不同的相对宽度,必须保持这种关系(这里开始我的问题)
- 每个列的居中都不相同(在文档中找不到如何实现这一点)
我现在的问题是setSectionResizeMode
和resizeSection
的使用冲突。我可以有不同的列宽或可拉伸的 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)
我正在尝试实现类似于以下的 pyqt5 table:
首先:我什至不确定 QTableWidget 是最合适的小部件,因为我对 Qt 没有太多经验。 QGridLayout 可能更合适。我首先尝试了它,但不知何故我不知道如何让它满足要求,任何建议将不胜感激。
table 要求是:
- 一些单元格包含文本,一些 QCheckBoxes 和一些 QRadioButtons
- table 宽度在调整大小时必须始终填充其父级宽度的 100%(我目前正在使用
setSectionResizeMode(QHeaderView.Stretch)
) - table 应该可以垂直滚动
- 它的某些列具有不同的相对宽度,必须保持这种关系(这里开始我的问题)
- 每个列的居中都不相同(在文档中找不到如何实现这一点)
我现在的问题是setSectionResizeMode
和resizeSection
的使用冲突。我可以有不同的列宽或可拉伸的 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)