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

如何在QTreeView中禁用指定行的展开功能(保留选中权限)

解决QTreeView指定行隐藏展开箭头但保留选中功能的问题

原代码尝试通过修改QStyledItemDelegate的sizeHint来隐藏展开箭头,这种方法无效——因为展开箭头属于QTreeView的分支装饰(branch),并不归item delegate负责绘制,修改item的尺寸不会影响箭头的显示。

下面提供两种可行的解决方案:

方法一:重写QTreeView的drawBranches方法

直接控制箭头的绘制逻辑,指定行不绘制展开箭头:

import sys
from PySide2.QtWidgets import QApplication, QMainWindow, QTreeView, QVBoxLayout, QWidget, QAbstractItemView, QSizePolicy
from PySide2.QtCore import Qt, QModelIndex, QRect
from PySide2.QtGui import QPainter

class CustomTreeView(QTreeView):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.target_row = 5  # 要隐藏箭头的行索引

    def drawBranches(self, painter: QPainter, rect: QRect, index: QModelIndex) -> None:
        # 仅当不是目标行时,才绘制展开箭头
        if index.row() != self.target_row:
            super().drawBranches(painter, rect, index)

class CustomItemModel(QAbstractItemModel):
    def __init__(self, data, parent=None):
        super().__init__(parent)
        self.data = data
        self.max_display_rows = 5

    def index(self, row, column, parent=QModelIndex()):
        if parent.isValid() or column != 0:
            return QModelIndex()
        return self.createIndex(row, column, row)

    def parent(self, index):
        return QModelIndex()

    def rowCount(self, parent=QModelIndex()):
        if parent.isValid():
            return 0
        return len(self.data)

    def columnCount(self, parent=QModelIndex()):
        return 1

    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid():
            return None
        if role == Qt.DisplayRole:
            return self.data[index.row()]
        return None

    def flags(self, index):
        # 确保所有行都可选中,目标行也不例外
        flags = super().flags(index)
        flags |= Qt.ItemIsSelectable | Qt.ItemIsEnabled
        # 如果需要目标行实际不可展开,可去掉ItemIsExpandable;如果只是隐藏箭头保留展开功能,不要改这行
        # if index.row() == self.max_display_rows:
        #     flags &= ~Qt.ItemIsExpandable
        return flags

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Custom TreeView Example")
        self.setGeometry(100, 100, 400, 300)

        data = ["Item {}".format(i) for i in range(1, 11)]

        self.model = CustomItemModel(data)
        self.treeView = CustomTreeView()
        self.treeView.setModel(self.model)
        self.treeView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.treeView.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        layout = QVBoxLayout()
        layout.addWidget(self.treeView)

        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

def main():
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

方法二:通过模型flags控制(适合目标行无需展开功能的场景)

如果目标行本身不需要展开功能,可以在模型的flags方法中移除Qt.ItemIsExpandable标记,这样箭头会自动隐藏,同时保留选中功能:

# 在CustomItemModel的flags方法中修改:
def flags(self, index):
    flags = super().flags(index)
    flags |= Qt.ItemIsSelectable | Qt.ItemIsEnabled
    # 目标行移除可展开标记,箭头会隐藏
    if index.row() == self.max_display_rows:
        flags &= ~Qt.ItemIsExpandable
    return flags

说明

  • 方法一的优势是:即使目标行实际有子项(可展开),也能只隐藏箭头,保留展开功能(点击行仍可展开,只是看不到箭头)。
  • 方法二更简洁,但会同时禁用该行的展开功能,适合确定不需要展开的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 22:54:53