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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 16:25:57