Qt QML创建二叉树时无法通过objectName查找子组件求助
Qt QML二叉树插入节点问题:递归插入第三个节点时无法找到已创建的左子节点
我正在开发一个用于教学的Qt QML二叉树项目,支持根据用户输入创建节点。目前仅实现了左子树的递归插入逻辑(仅处理小于父节点的值),但插入第三个节点时出现异常:根节点和第二个节点插入正常,但插入第三个节点时,递归查找已创建的第二个节点失败,控制台打印left_node doesn't exist。
核心代码
插入节点函数
void BinaryTree::insert_node(QQuickItem* parent_node, QString node_text) { double node_value = node_text.toDouble(); root_node_value = parent_node->property("node_text").toInt(); if (node_value < root_node_value) { if (!parent_node->property("has_left_node").toBool()) { QQuickItem *left_node = create_binary_node(parent_node, node_text, "left_node"); QObject *node_anchors = qvariant_cast<QObject*>(left_node->property("anchors")); node_anchors->setProperty("right", parent_node->property("right")); node_anchors->setProperty("rightMargin", 60); left_node->setProperty("id", "left_node"); left_node->setProperty("objectName", "left_node"); parent_node->setProperty("has_left_node", true); } else { QQuickItem* left_node = parent_node->findChild<QQuickItem*>("left_node"); if (left_node) { insert_node(left_node, node_text); } else { std::cout << "left_node doesn't exist" << std::endl; } } } };
创建节点相关函数
void BinaryTree::create_node(QString node_text) { if (node_count == 0) { double node_value = node_text.toDouble(); QString node_id = "node_" + QString::number(node_count); QQuickItem *node = qobject_cast<QQuickItem*>(node_component->create()); node->setParentItem(qobject_cast<QQuickItem*>(node_parent)); node->setProperty("node_text", node_text); node->setProperty("id", node_id); QObject *node_anchors = qvariant_cast<QObject*>(node->property("anchors")); node_anchors->setProperty("horizontalCenter", node_parent->property("horizontalCenter")); node_anchors->setProperty("top", node_parent->property("top")); node_anchors->setProperty("topMargin", 10); root_node = node; root_node_value = node_value; } else { insert_node(root_node, node_text); } node_count++; }; QQuickItem* BinaryTree::create_binary_node(QQuickItem* parent_node, QString node_text, QString node_id) { QQuickItem* node = qobject_cast<QQuickItem*>(node_component->create()); node->setParentItem(parent_node); node->setProperty("node_text", node_text); node->setProperty("id", node_id); node->setProperty("objectName", node_id); QObject *node_anchors = qvariant_cast<QObject*>(node->property("anchors")); node_anchors->setProperty("top", parent_node->property("top")); node_anchors->setProperty("topMargin", 60); return node; }
QML节点组件
Rectangle { width: 50 height: 50 radius: Math.min(width, height)/2 color: "cyan" property string node_text property bool has_right_node: false property bool has_left_node: false Text { font.pixelSize: 12 anchors.centerIn: parent text: node_text } }
排查方向与已尝试方法
可能原因
- 创建的节点超出作用域,导致后续迭代无法找到
- 节点
objectName赋值存在错误(已在函数外重复设置objectName和id)
已尝试方法
- 打印新创建节点的属性,确认
objectName存在 - 添加条件语句检查
findChild返回值
解决方案
1. 修改QML组件,添加子节点引用属性
在QML节点中直接存储左/右子节点的引用,避免通过findChild查找:
Rectangle { width: 50 height: 50 radius: Math.min(width, height)/2 color: "cyan" property string node_text property bool has_right_node: false property bool has_left_node: false property Item left_node // 存储左子节点引用 property Item right_node // 存储右子节点引用 Text { font.pixelSize: 12 anchors.centerIn: parent text: node_text } }
2. 重构C++插入逻辑,直接使用子节点引用
不再依赖findChild,通过父节点的属性直接获取/设置子节点:
void BinaryTree::insert_node(QQuickItem* parent_node, QString node_text) { double node_value = node_text.toDouble(); // 统一用toDouble避免整数转换丢失精度 double parent_value = parent_node->property("node_text").toDouble(); if (node_value < parent_value) { if (!parent_node->property("has_left_node").toBool()) { // 用节点值生成唯一标识,避免objectName重复 QString unique_node_id = "left_node_" + node_text; QQuickItem *left_node = create_binary_node(parent_node, node_text, unique_node_id); QObject *node_anchors = qvariant_cast<QObject*>(left_node->property("anchors")); node_anchors->setProperty("right", parent_node->property("right")); node_anchors->setProperty("rightMargin", 60); // 直接将子节点赋值给父节点的left_node属性 parent_node->setProperty("left_node", QVariant::fromValue(left_node)); parent_node->setProperty("has_left_node", true); } else { // 直接从父节点属性获取左子节点 QQuickItem* left_node = qvariant_cast<QQuickItem*>(parent_node->property("left_node")); if (left_node) { insert_node(left_node, node_text); } else { std::cout << "left_node reference is null" << std::endl; } } } };
3. 优化节点创建函数(可选)
避免重复设置相同的objectName,用唯一标识命名:
QQuickItem* BinaryTree::create_binary_node(QQuickItem* parent_node, QString node_text, QString node_id) { QQuickItem* node = qobject_cast<QQuickItem*>(node_component->create()); node->setParentItem(parent_node); node->setProperty("node_text", node_text); node->setProperty("objectName", node_id); QObject *node_anchors = qvariant_cast<QObject*>(node->property("anchors")); node_anchors->setProperty("top", parent_node->property("top")); node_anchors->setProperty("topMargin", 60); return node; }
问题根源说明
原代码依赖findChild查找同名objectName的节点,但所有左子节点的objectName均为left_node,当递归到深层节点时,findChild可能返回错误的节点(或因QML节点初始化时序问题导致查找失败)。直接在父节点中存储子节点引用是更可靠的方式,彻底避免查找逻辑的不确定性。
内容的提问来源于stack exchange,提问作者Zues
相关产品推荐
相关产品推荐

