问题描述
我正在PyQt5
所在的QTableWidget
工作。它有一个标题列,我想自动换行。下面是表格的样子:
我们可以看到,像Maximum Variation Coefficient
这样的标头标签有3个字,因此占用了过多的列宽。如何将单词包装在标题中。
下面是代码:
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
# Main Window
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'PyQt5 - QTableWidget'
self.left = 0
self.top = 0
self.width = 300
self.height = 200
self.setwindowTitle(self.title)
self.setGeometry(self.left,self.top,self.width,self.height)
self.createTable()
self.layout = QVBoxLayout()
self.layout.addWidget(self.tableWidget)
self.setLayout(self.layout)
# Show window
self.show()
# Create table
def createTable(self):
self.tableWidget = QTableWidget()
# Row count
self.tableWidget.setRowCount(3)
# Column count
self.tableWidget.setColumnCount(2)
self.tableWidget.setHorizontalHeaderLabels(["Maximum Variation Coefficient","Maximum Variation Coefficient"])
self.tableWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.ResizetoContents)
self.tableWidget.setItem(0,QTableWidgetItem("3.44"))
self.tableWidget.setItem(0,1,QTableWidgetItem("5.3"))
self.tableWidget.setItem(1,QTableWidgetItem("4.6"))
self.tableWidget.setItem(1,QTableWidgetItem("1.2"))
self.tableWidget.setItem(2,QTableWidgetItem("2.2"))
self.tableWidget.setItem(2,QTableWidgetItem("4.4"))
# Table will fit the screen horizontally
self.tableWidget.horizontalHeader().setStretchLastSection(True)
self.tableWidget.horizontalHeader().setSectionResizeMode(
QHeaderView.Stretch)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
我尝试添加此self.tableWidget.setWordWrap(True)
,但这并没有做任何更改。任何人都可以提供一些好的解决方案。请帮忙。谢谢
编辑:
也尝试过这个:
self.tableWidget.horizontalHeader().setDefaultAlignment(QtCore.Qt.AlignHCenter | Qt.Alignment(QtCore.Qt.TextWordWrap))
但是没有用
解决方法
为了实现所需的功能,必须设置自己的标头并继续以下两个假设:
- 如果列的 width 不足,则标题必须根据节内容提供正确的大小提示 height ;
- 文本对齐方式必须包含
QtCore.Qt.TextWordWrap
标志,以便绘画者知道它可以包装文本;
第一点需要继承QHeaderView的子类并重新实现sectionSizeFromContents()
:
class WrapHeader(QtWidgets.QHeaderView):
def sectionSizeFromContents(self,logicalIndex):
# get the size returned by the default implementation
size = super().sectionSizeFromContents(logicalIndex)
if self.model():
if size.width() > self.sectionSize(logicalIndex):
text = self.model().headerData(logicalIndex,self.orientation(),QtCore.Qt.DisplayRole)
if not text:
return size
# in case the display role is numeric (for example,when header
# labels are not defined yet),convert it to a string;
text = str(text)
option = QtWidgets.QStyleOptionHeader()
self.initStyleOption(option)
alignment = self.model().headerData(logicalIndex,QtCore.Qt.TextAlignmentRole)
if alignment is None:
alignment = option.textAlignment
# get the default style margin for header text and create a
# possible rectangle using the current section size,then use
# QFontMetrics to get the required rectangle for the wrapped text
margin = self.style().pixelMetric(
QtWidgets.QStyle.PM_HeaderMargin,option,self)
maxWidth = self.sectionSize(logicalIndex) - margin * 2
rect = option.fontMetrics.boundingRect(
QtCore.QRect(0,maxWidth,10000),alignment | QtCore.Qt.TextWordWrap,text)
# add vertical margins to the resulting height
height = rect.height() + margin * 2
if height >= size.height():
# if the height is bigger than the one provided by the base
# implementation,return a new size based on the text rect
return QtCore.QSize(rect.width(),height)
return size
class App(QWidget):
# ...
def createTable(self):
self.tableWidget = QTableWidget()
self.tableWidget.setHorizontalHeader(
WrapHeader(QtCore.Qt.Horizontal,self.tableWidget))
# ...
然后,要设置自动换行标志,有两个选项:
- 使用每个现有列的
setHeaderData()
在基础模型上设置对齐标记:
# ...
model = self.tableWidget.model()
default = self.tableWidget.horizontalHeader().defaultAlignment()
default |= QtCore.Qt.TextWordWrap
for col in range(self.tableWidget.columnCount()):
alignment = model.headerData(
col,QtCore.Qt.Horizontal,QtCore.Qt.TextAlignmentRole)
if alignment:
alignment |= QtCore.Qt.TextWordWrap
else:
alignment = default
model.setHeaderData(
col,alignment,QtCore.Qt.TextAlignmentRole)
- 通过在选项上应用标志,使用QProxyStyle覆盖标题的绘制:
# ...
class ProxyStyle(QtWidgets.QProxyStyle):
def drawControl(self,control,painter,widget=None):
if control in (self.CE_Header,self.CE_HeaderLabel):
option.textAlignment |= QtCore.Qt.TextWordWrap
super().drawControl(control,widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle(ProxyStyle())
ex = App()
sys.exit(app.exec_())
最后,请考虑将setSectionResizeMode
或ResizeToContents
与Stretch
一起使用,将始终导致表尝试使用标头所需的空间第一次显示时。