使用 PyQt/PySide 禁用 QTableWidget 中特定列中的排序箭头

Disable the sort arrow in a specific column in QTableWidget with PyQt/PySide

我想从第一列标题中删除箭头,使标题与复选框居中。所有这一切都没有禁用对列进行排序的可能性。

这是我当前的代码。

import sys

from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
    QApplication,
    QProxyStyle,
    QStyle,
    QTableWidget,
    QTableWidgetItem,
)


class ProxyStyle(QProxyStyle):
    def subElementRect(self, e, opt, widget):
        r = super().subElementRect(e, opt, widget)
        if e == QStyle.SE_ItemViewItemCheckIndicator:
            r.moveCenter(opt.rect.center())
        return r


class Table(QTableWidget):
    def __init__(self):
        QTableWidget.__init__(self, 3, 1)
        self._style = ProxyStyle(self.style())
        self.setStyle(self._style)
        for i in range(self.rowCount()):
            for j in range(self.columnCount()):
                it = QTableWidgetItem()
                self.setItem(i, j, it)
                it.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable)
                it.setCheckState(Qt.Checked if (i + j) % 2 == 0 else Qt.Unchecked)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = Table()
    w.show()
    sys.exit(app.exec_())

最简单的解决方案是覆盖 drawControl() 并将 QStyleOptionHeader 的 indicator 设置为 0(如果该列与您要隐藏的列匹配)。

class ProxyStyle(QProxyStyle):
    # ...
    def drawControl(self, ctl, opt, qp, widget=None):
        if ctl == QStyle.CE_HeaderSection and opt.orientation == Qt.Horizontal:
            if opt.section == widget.parent().property('hideSortIndicatorColumn'):
                opt.sortIndicator = 0
        super().drawControl(ctl, opt, qp, widget)


class Table(QTableWidget):
    def __init__(self):
        # ...
        self.setProperty('hideSortIndicatorColumn', 0)

请注意,对于具有子项的复杂小部件,在小部件上设置样式并不总是足够的。
在你的情况下它起作用是因为你将当前样式添加到代理构造函数,但这意味着样式的所有权将 completely 由代理获取,并且任何其他 QWidget 将使用从那一刻开始代理(这几乎与将代理设置为整个应用程序相同)。
另一种方法是创建不带任何参数的代理(在这种情况下,将使用默认本机样式的 新实例),但这也意味着 no 小部件的子项将继承样式,因为 QStyles 不会传播给它们的子项。