QTreeView 中的列对齐 | PyQt5
Column Alignment in QTreeView | PyQt5
如何水平对齐 QTreeView 的一列(该列的所有项目)?我正在使用 QStandardItemModel()。我已经搜索过,但没有找到任何相关文档。
提前致谢!
注意:建议的解决方案仅适用于 OP 要求的基本情况(简单的 QStandardItemModel 或提供基本模型数据显示的任何子类模型);在这个答案的底部阅读更多内容
您可以子类化模型并重写 data()
函数,以便在请求 Qt.TextAlignmentRole
时 return 适当的 Qt.AlignmentFlag,默认情况下,它是None 除非用 setData()
或 item.setTextAlignment()
手动设置:当 returned 值为 None
时,对齐方式由 view,通常基于系统的布局方向。
在下面的示例中,您可以为任何列(或使用 None
恢复它)设置任意 default 对齐方式,除非对齐方式有已明确设置为如上所述。
class AlignModel(QtGui.QStandardItemModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.columnAlignments = {}
def setColumnAlignment(self, column, alignment):
if alignment:
self.columnAlignments[column] = alignment
elif column in self.columnAlignments:
self.columnAlignments.pop(column)
def data(self, index, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.TextAlignmentRole:
return (super().data(index, role) or
self.columnAlignments.get(index.column()))
return super().data(index, role)
# set the center alignment for the *second* column:
model = AlignModel()
model.setColumnAlignment(1, QtCore.Qt.AlignCenter)
请注意,Qt.AlignCenter
意味着 Qt.AlignVCenter
和 Qt.AlignHCenter
(通过 OR 运算符),因此如果要向右或向左对齐,还必须提供垂直对齐:例如,Qt.AlignRight|Qt.AlignVCenter
.
一些重要说明:
作为 ,常见的建议是使用委托而不是对模型进行子类化。虽然我的解决方案适用于需要非常简单的解决方案(并且可以实际使用模型,但更高级别 类、QTreeWidget、QTableWidget 和 QListWidget 并非如此)的情况,但一般规则是模型应该 never return “更改”内容:来自 data()
的 returned 值应该始终反映索引的实际内容,并且任何修改(包括显示文本对齐等数据)应该使用代理模型或通过更改委托的行为来进行。
从 OOP 的典型模块化观点来看,这是非常重要的,特别是考虑到 MVC(或 MV,对于 Qt)模式:模型(真实 数据)和视图(如何显示数据)应该是不同的和独立的。
以这种情况为例:文本对齐。让我们假设对齐应该朝向第一列的“开始”:对于从右到左的语言,这意味着将文本对齐在右边(因为第一列在右边缘);如果模型要被序列化,结果是对齐将依赖于序列化的 source 布局,而对齐应该完全依赖于用户查看的布局(反序列化)它。
所以,这就是您应该问的问题:文本对齐对于模型(例如,数据可能包含具有不同书写方向的各种语言的文本)或视图重要吗?如果这些都不重要,那么你必须考虑什么是最好的解决方案,性能方面:例如,如果你要有一个非常大的模型(有数千个条目,可能有数百个项目)同时显示),并且您确定某个列将始终具有相同的对齐方式,那么您可以覆盖 data()
或使用 QIdentityProxyModel,这肯定比使用委托和覆盖更快paint
方法。
在任何其他情况下,委托解决方案是更正确和连贯的解决方案,因为它还允许以不同方式显示相同的模型数据,无论内容是什么。
不涉及从模型继承的解决方案(这有时是一个限制,例如 QListWidget、QTableWidget 或 QTreeWidget)是:
- 使用代理模型(例如 QIdentityProxyModel)。
- 使用代表。
在这种情况下,我将使用最后一种解决方案:
from functools import cached_property
class AlignmentDelegate(QStyledItemDelegate):
@cached_property
def alignment(self):
return dict()
def set_column_alignment(self, column, alignment):
self.alignment[column] = alignment
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
alignment = self.alignment.get(index.column(), None)
if alignment is not None:
option.displayAlignment = alignment
delegate = AlignmentDelegate(self.view)
self.view.setItemDelegate(delegate)
delegate.set_column_alignment(1, QtCore.Qt.AlignCenter)
前一种方法的优点是可以适用于任何模型,修改方便
如何水平对齐 QTreeView 的一列(该列的所有项目)?我正在使用 QStandardItemModel()。我已经搜索过,但没有找到任何相关文档。 提前致谢!
注意:建议的解决方案仅适用于 OP 要求的基本情况(简单的 QStandardItemModel 或提供基本模型数据显示的任何子类模型);在这个答案的底部阅读更多内容
您可以子类化模型并重写 data()
函数,以便在请求 Qt.TextAlignmentRole
时 return 适当的 Qt.AlignmentFlag,默认情况下,它是None 除非用 setData()
或 item.setTextAlignment()
手动设置:当 returned 值为 None
时,对齐方式由 view,通常基于系统的布局方向。
在下面的示例中,您可以为任何列(或使用 None
恢复它)设置任意 default 对齐方式,除非对齐方式有已明确设置为如上所述。
class AlignModel(QtGui.QStandardItemModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.columnAlignments = {}
def setColumnAlignment(self, column, alignment):
if alignment:
self.columnAlignments[column] = alignment
elif column in self.columnAlignments:
self.columnAlignments.pop(column)
def data(self, index, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.TextAlignmentRole:
return (super().data(index, role) or
self.columnAlignments.get(index.column()))
return super().data(index, role)
# set the center alignment for the *second* column:
model = AlignModel()
model.setColumnAlignment(1, QtCore.Qt.AlignCenter)
请注意,Qt.AlignCenter
意味着 Qt.AlignVCenter
和 Qt.AlignHCenter
(通过 OR 运算符),因此如果要向右或向左对齐,还必须提供垂直对齐:例如,Qt.AlignRight|Qt.AlignVCenter
.
一些重要说明:
作为 data()
的 returned 值应该始终反映索引的实际内容,并且任何修改(包括显示文本对齐等数据)应该使用代理模型或通过更改委托的行为来进行。
从 OOP 的典型模块化观点来看,这是非常重要的,特别是考虑到 MVC(或 MV,对于 Qt)模式:模型(真实 数据)和视图(如何显示数据)应该是不同的和独立的。
以这种情况为例:文本对齐。让我们假设对齐应该朝向第一列的“开始”:对于从右到左的语言,这意味着将文本对齐在右边(因为第一列在右边缘);如果模型要被序列化,结果是对齐将依赖于序列化的 source 布局,而对齐应该完全依赖于用户查看的布局(反序列化)它。
所以,这就是您应该问的问题:文本对齐对于模型(例如,数据可能包含具有不同书写方向的各种语言的文本)或视图重要吗?如果这些都不重要,那么你必须考虑什么是最好的解决方案,性能方面:例如,如果你要有一个非常大的模型(有数千个条目,可能有数百个项目)同时显示),并且您确定某个列将始终具有相同的对齐方式,那么您可以覆盖 data()
或使用 QIdentityProxyModel,这肯定比使用委托和覆盖更快paint
方法。
在任何其他情况下,委托解决方案是更正确和连贯的解决方案,因为它还允许以不同方式显示相同的模型数据,无论内容是什么。
不涉及从模型继承的解决方案(这有时是一个限制,例如 QListWidget、QTableWidget 或 QTreeWidget)是:
- 使用代理模型(例如 QIdentityProxyModel)。
- 使用代表。
在这种情况下,我将使用最后一种解决方案:
from functools import cached_property
class AlignmentDelegate(QStyledItemDelegate):
@cached_property
def alignment(self):
return dict()
def set_column_alignment(self, column, alignment):
self.alignment[column] = alignment
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
alignment = self.alignment.get(index.column(), None)
if alignment is not None:
option.displayAlignment = alignment
delegate = AlignmentDelegate(self.view)
self.view.setItemDelegate(delegate)
delegate.set_column_alignment(1, QtCore.Qt.AlignCenter)
前一种方法的优点是可以适用于任何模型,修改方便