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

Qt:能否在QTreeWidget成为父控件前为QTreeWidgetItem设置ItemWidget?

递归填充QTreeWidget时SpinBox不显示的最小修复方案

问题描述

我写了一个递归函数从JSON文件填充QTreeWidget,基础功能正常,但值列的SpinBox控件始终不显示。代码里先创建QTreeWidgetItem,返回给上层添加为子项后才设置SpinBox,导致控件无法正常显示,求改动最小的解决办法。

原代码:

QTreeWidgetItem MainWindow::treeItemFromJson(QTreeWidgetItem* root, QJsonValue val){
    QJsonObject obj = val.toObject();
    foreach(const QString &key, obj.keys()){
        if(obj.value(key).isObject()){
            QTreeWidgetItem* item = new QTreeWidgetItem({key});
            treeItemFromJson(item, obj.value(key));
            root->addChild(item); // item containing spinBox is set as child AFTER
        }
        else { // if the value stored in an object is not another object, then it is a setting

            switch(obj.value("Value").type()){
                case QJsonValue::Double  :
                    QSpinBox * spinBox;
                    spinBox = new QSpinBox();
                    spinBox->setRange(obj.value("Minimum").toInt(), obj.value("Maximum").toInt());
                    spinBox->setValue(obj.value("Value").toInt());
                    ui->settingsTree->setItemWidget(root, 1, spinBox);
                break;
                case QJsonValue::Bool :
                    QRadioButton * radioButton;
                    radioButton = new QRadioButton("test");
                    ui->settingsTree->setItemWidget(root, 1, radioButton);
                break;
                default :
                    root->setData(1, Qt::DisplayRole, obj.value("Value"));
                break;
            }

            root->setData(2, Qt::DisplayRole, obj.value("Unit"));
            root->setData(3, Qt::DisplayRole, obj.value("Description"));
            root->setData(4, Qt::DisplayRole, obj.value("Minimum"));
            root->setData(5, Qt::DisplayRole, obj.value("Maximum"));
            root->setData(6, Qt::DisplayRole, obj.value("Default"));
            root->setData(7, Qt::DisplayRole, obj.value("Identifier"));
        }
    }
    return *new QTreeWidgetItem; // useless
}

修复方案(改动极小)

核心问题有三个:

  1. 逻辑错误:else分支里错误地取obj.value("Value"),但此时obj.value(key)不是对象,根本没有Value键,导致switch直接走default,控件没被创建。
  2. 控件绑定错误:就算控件创建了,也被设置给了当前root节点,而非新建的叶子节点。
  3. 无用返回值:函数末尾返回的*new QTreeWidgetItem完全没被用到,纯粹浪费内存。

直接修改这几点即可,改动量极小:

// 把返回值改成void,原返回完全无用
void MainWindow::treeItemFromJson(QTreeWidgetItem* root, QJsonValue val){
    QJsonObject obj = val.toObject();
    foreach(const QString &key, obj.keys()){
        QJsonValue currentVal = obj.value(key);
        if(currentVal.isObject()){
            QJsonObject currentObj = currentVal.toObject();
            // 判断当前对象是叶子节点(含Value字段)还是分支节点
            if(currentObj.contains("Value")){
                // 新建叶子节点,第一列显示key
                QTreeWidgetItem* leafItem = new QTreeWidgetItem({key});
                // 根据Value类型创建对应控件
                switch(currentObj.value("Value").type()){
                    case QJsonValue::Double  :
                        QSpinBox * spinBox = new QSpinBox();
                        spinBox->setRange(currentObj.value("Minimum").toInt(), currentObj.value("Maximum").toInt());
                        spinBox->setValue(currentObj.value("Value").toInt());
                        // 把控件绑定到新建的叶子节点
                        ui->settingsTree->setItemWidget(leafItem, 1, spinBox);
                    break;
                    case QJsonValue::Bool :
                        QRadioButton * radioButton = new QRadioButton("test");
                        ui->settingsTree->setItemWidget(leafItem, 1, radioButton);
                    break;
                    default :
                        leafItem->setData(1, Qt::DisplayRole, currentObj.value("Value"));
                    break;
                }
                // 给叶子节点设置其他字段数据
                leafItem->setData(2, Qt::DisplayRole, currentObj.value("Unit"));
                leafItem->setData(3, Qt::DisplayRole, currentObj.value("Description"));
                leafItem->setData(4, Qt::DisplayRole, currentObj.value("Minimum"));
                leafItem->setData(5, Qt::DisplayRole, currentObj.value("Maximum"));
                leafItem->setData(6, Qt::DisplayRole, currentObj.value("Default"));
                leafItem->setData(7, Qt::DisplayRole, currentObj.value("Identifier"));
                // 将叶子节点添加到root的子项
                root->addChild(leafItem);
            } else {
                // 分支节点逻辑保留,递归处理子项
                QTreeWidgetItem* item = new QTreeWidgetItem({key});
                treeItemFromJson(item, currentVal);
                root->addChild(item);
            }
        }
        else {
            // 单纯基础值的情况,直接创建叶子节点显示
            QTreeWidgetItem* leafItem = new QTreeWidgetItem({key});
            leafItem->setData(1, Qt::DisplayRole, currentVal);
            root->addChild(leafItem);
        }
    }
    // 删除无用的返回语句
}

关键改动点

  • 函数返回值改为void,移除末尾无用的返回代码。
  • 正确区分分支节点(不含Value字段的对象)和叶子节点(含Value字段的对象),修正原逻辑错误。
  • 所有控件和数据都绑定到新建的叶子节点,再将叶子节点添加到root子项,确保控件与节点关联正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 05:37:46