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

Posted

技术标签:

【中文标题】使用 PyQt/PySide 禁用 QTableWidget 中特定列中的排序箭头【英文标题】:Disable the sort arrow in a specific column in QTableWidget with PyQt/PySide 【发布时间】:2020-12-18 11:07:11 【问题描述】:

我想从第一列标题中删除箭头,以便标题以复选框为中心。所有这些都不会禁用对列进行排序的可能性。

这是我当前的代码。

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_())

【问题讨论】:

【参考方案1】:

最简单的解决方案是覆盖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)

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

【讨论】:

它与 PyQt5 完美配合,但我有 AttributeError: 'PySide6.QtWidgets.QStyleOption' object has no attribute 'section'AttributeError: 'PySide6.QtWidgets.QStyleOption' object has no attribute 'orientation' 与 PySide。 Mh。我知道在当前过渡到 Qt6 期间正在进行一些更改(如果你真的不需要它,这是一个很好的理由现在避免它)。您完全使用了我的代码吗?为了安全起见,您可以确保 optQStyleOptionHeader 类型。 opt.rectopt.directionnot 我正在使用的:opt.rect 是绘画发生的矩形,direction书写方向(用于从右到左的语言),并且 PySide 的属性也相同(包括 PySide6):doc.qt.io/qtforpython/PySide6/QtWidgets/QStyleOptionHeader.html 它仅适用于 PyQt5,opt 始终为 QStyleOption 与 PySide2 和 PySide6。 @0lan 我现在无法使用 PySide,如果您尝试使用当前选项创建一个新选项怎么办? newopt = QtWidgets.QStyleOptionHeader(opt) 然后将 newopt 用于函数的其余部分。

以上是关于使用 PyQt/PySide 禁用 QTableWidget 中特定列中的排序箭头的主要内容,如果未能解决你的问题,请参考以下文章

将 vtkOrientationMarkerWidget 与 QVTKRenderWindowInteractor 一起使用 [PyQt4/PySide]

PyQt/Pyside - 也使用 valueChanged 返回先前的值

如何使用线程自动关闭 PyQt/PySide 窗口?

如何使用 PyQt/PySide 获取与特定文件类型关联的图标?

关闭 PyQt 对话框会终止父进程? (PyQt4 / Pyside) 带有示例代码

PyQt / PySide - 小部件的实际大小