You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt中QStyledItemDelegate绘制复选框时穿透显示问题求助

问题分析与解决

问题根源在于自定义paint方法未正确处理控件背景绘制,导致列调整后之前的复选框绘制内容未被覆盖,出现穿透显示的情况;同时绘制时未严格限定在当前列的可视区域内。

修复后的代码

import sys
from PyQt5 import QtCore, QtWidgets


class CustomTreeWidgetDelegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None) -> None:
        super().__init__(parent)

    def paint(self, painter, option, index):
        options = QtWidgets.QStyleOptionViewItem(option)
        self.initStyleOption(options, index)

        if options.widget:
            style = option.widget.style()
        else:
            style = QtWidgets.QApplication.style()

        # 先绘制item背景,清除原有残留内容
        style.drawPrimitive(QtWidgets.QStyle.PE_PanelItemViewItem, options, painter, options.widget)

        # 仅在第0列绘制复选框
        if index.column() == 0:
            item_options = QtWidgets.QStyleOptionButton()
            item_options.initFrom(options.widget)
            item_options.state = (QtWidgets.QStyle.State_On | QtWidgets.QStyle.State_Enabled) if options.checkState == QtCore.Qt.Checked else (QtWidgets.QStyle.State_Off | QtWidgets.QStyle.State_Enabled)
            item_options.rect = style.subElementRect(QtWidgets.QStyle.SE_ViewItemCheckIndicator, options)
            # 裁剪绘制区域,确保只在当前item范围内绘制
            with painter.clipped(options.rect):
                QtWidgets.QApplication.style().drawControl(QtWidgets.QStyle.CE_CheckBox, item_options, painter)

        # 绘制文本
        text = index.data(QtCore.Qt.DisplayRole)
        if text:
            rect = style.subElementRect(QtWidgets.QStyle.SE_ItemViewItemText, options)
            elided_text = options.fontMetrics.elidedText(text, QtCore.Qt.ElideRight, rect.width())
            painter.drawText(rect, QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, elided_text)


if __name__ == "__main__":

    class MyTree(QtWidgets.QTreeWidget):
        def __init__(self):
            super().__init__()

            self.setItemDelegate(CustomTreeWidgetDelegate())

            head = self.headerItem()
            head.setText(0, "Name")
            head.setText(1, "Age")

            parent = QtWidgets.QTreeWidgetItem(self)
            parent.setCheckState(0, QtCore.Qt.Unchecked)
            parent.setText(0, "Jack Smith")
            parent.setText(1, "30")

            child = QtWidgets.QTreeWidgetItem(parent)
            child.setCheckState(0, QtCore.Qt.Checked)
            child.setText(0, "Jane Smith")
            child.setText(1, "10")
            self.expandAll()

    App = QtWidgets.QApplication(sys.argv)
    myTree = MyTree()
    myTree.show()
    sys.exit(App.exec())

关键修复点

  • 背景清除:添加style.drawPrimitive(QtWidgets.QStyle.PE_PanelItemViewItem, ...),每次绘制前先填充item背景,覆盖之前的残留绘制内容。
  • 区域裁剪:使用painter.clipped(options.rect)包裹复选框绘制逻辑,确保所有绘制操作严格限定在当前item的可视范围内,避免跨列穿透。
  • 逻辑简化:优化复选框状态判断逻辑,提升代码可读性。

内容的提问来源于stack exchange,提问作者LozzerJP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 05:30:59