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 }
修复方案(改动极小)
核心问题有三个:
- 逻辑错误:
else分支里错误地取obj.value("Value"),但此时obj.value(key)不是对象,根本没有Value键,导致switch直接走default,控件没被创建。 - 控件绑定错误:就算控件创建了,也被设置给了当前
root节点,而非新建的叶子节点。 - 无用返回值:函数末尾返回的
*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
相关产品推荐
相关产品推荐

