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

如何在QML TreeView中添加复选框并实现父子节点选中联动?

QML TreeView 复选框父子联动实现方案

要实现父节点勾选时自动联动所有子节点、子节点状态变化同步更新父节点状态的效果,按以下步骤修改即可:

前置准备

首先给你的树模型sysConfig的每个节点新增布尔类型的isChecked角色,用来存储节点选中状态。如果需要支持半选状态,该字段允许存null值代表半选。

核心逻辑

联动逻辑分两部分:

  • 父节点点击选中/取消选中时,递归遍历当前节点下所有层级的子节点,将所有子节点的选中状态和父节点保持一致
  • 任意子节点选中状态变化时,向上逐级遍历父节点,统计每个父节点下所有直接子节点的选中情况:子节点全选则父节点设为选中,子节点全不选则父节点设为未选中,子节点部分选中则父节点设为半选

完整实现代码

TreeView {
    id: treeView
    anchors.fill: parent
    frameVisible: false
    anchors.top: mainToolBar.bottom
    anchors.bottom: parent.bottom
    anchors.left: parent.left
    anchors.leftMargin: 1
    model: sysConfig

    // 递归设置当前节点及所有子节点选中状态
    function setChildCheckState(parentIndex, checkState) {
        const childCount = model.rowCount(parentIndex)
        // 更新当前节点状态
        model.setData(parentIndex, checkState, Qt.UserRole + 1)
        // 遍历处理所有子节点
        for(let i = 0; i < childCount; i++) {
            const childIndex = model.index(i, 0, parentIndex)
            setChildCheckState(childIndex, checkState)
        }
        // 子节点更新完成后同步父节点状态
        updateParentCheckState(parentIndex)
    }

    // 向上递归更新所有父节点的选中/半选状态
    function updateParentCheckState(childIndex) {
        const parentIndex = childIndex.parent
        // 到达根节点,终止递归
        if(!parentIndex.isValid) return

        const childCount = model.rowCount(parentIndex)
        let checkedNum = 0
        let uncheckedNum = 0
        // 统计当前父节点下所有直接子节点的选中情况
        for(let i = 0; i < childCount; i++) {
            const currentIdx = model.index(i, 0, parentIndex)
            const currentState = model.data(currentIdx, Qt.UserRole + 1)
            if(currentState === true) checkedNum++
            else if(currentState === false) uncheckedNum++
            else {
                // 存在半选子节点,当前父节点直接判定为半选
                checkedNum = 1
                uncheckedNum = 1
                break
            }
        }

        let parentState
        if(checkedNum === childCount) parentState = true
        else if(uncheckedNum === childCount) parentState = false
        else parentState = null

        model.setData(parentIndex, parentState, Qt.UserRole + 1)
        // 继续向上更新更高层级父节点
        updateParentCheckState(parentIndex)
    }

    itemDelegate: CheckBox {
        id: checkbox
        width: parent.width
        indicator.height: 20
        indicator.width: 20
        text: styleData.value

        // 绑定模型存储的状态
        checked: model.data(styleData.index, Qt.UserRole + 1) === true
        partiallyChecked: model.data(styleData.index, Qt.UserRole + 1) === null

        onClicked: {
            // 仅用户手动点击时触发联动,避免代码修改状态导致循环触发
            treeView.setChildCheckState(styleData.index, checked)
        }
    }
}

注意事项

  • 代码中Qt.UserRole + 1是自定义C++模型中isChecked角色对应的枚举值,如果你自己实现的QAbstractItemModel子类中给isChecked分配的角色值不是这个,替换成对应值即可。如果是用QML原生ListModel配合TreeView使用,直接通过model.isChecked访问即可,不需要写角色偏移值。
  • 联动逻辑必须放在CheckBox的onClicked信号中处理,不要写在onCheckedChanged里,后者会在代码修改checked状态时也触发,极易引发递归死循环。
  • 半选状态不需要单独持久化存储,每次子节点状态变化时动态计算父节点状态即可,减少状态维护成本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 13:15:48