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

基于QAbstractItemModel实现Family_tree树形显示异常求助

QTreeView仅显示‘1’且无图标问题排查与修复

你的TreeModel实现存在几个关键逻辑错误,导致QTreeView无法正确渲染树形结构和图标,以下是具体问题和修复方案:

1. rowCount方法顶层节点逻辑错误

当前rowCount中,父索引无效时(对应树形结构的顶层节点),你返回的是根节点的子节点数量,但实际上顶层节点应该是根节点本身,此时应返回1(顶层仅包含根节点)。

错误代码:

int TreeModel::rowCount(const QModelIndex& parent) const {
    node* parentNode;
    if (parent.column() > 0) {return 0;}

    if (!parent.isValid()) {parentNode = ft_.get_root();}
    else {parentNode = static_cast<node*>(parent.internalPointer());}

    return parentNode->getChildren().size();
}

修复后代码:

int TreeModel::rowCount(const QModelIndex& parent) const {
    if (parent.column() > 0) {return 0;}

    if (!parent.isValid()) {
        // 顶层节点为根节点,返回1
        return 1;
    } else {
        node* parentNode = static_cast<node*>(parent.internalPointer());
        return parentNode->getChildren().size();
    }
}

2. index方法顶层节点处理错误

当前index方法中,父索引无效时直接取根节点的子节点,但此时父索引无效对应顶层的根节点请求,应直接返回根节点的索引(仅当row为0时)。

错误代码:

QModelIndex TreeModel::index(int row, int column, const QModelIndex& parent) const {
    if (!hasIndex(row, column, parent)) {return QModelIndex();}

    node* parentNode;
    if (!parent.isValid()) {parentNode = ft_.get_root();}
    else {parentNode = static_cast<node*>(parent.internalPointer());}

    node* childNode = parentNode->getChildren()[row];
    if (childNode) {return createIndex(row, column, childNode);}
    else {return QModelIndex();}
}

修复后代码:

QModelIndex TreeModel::index(int row, int column, const QModelIndex& parent) const {
    if (!hasIndex(row, column, parent)) {return QModelIndex();}

    if (!parent.isValid()) {
        // 顶层节点请求,仅row=0有效,返回根节点索引
        if (row == 0) {
            return createIndex(row, column, ft_.get_root());
        }
        return QModelIndex();
    }

    node* parentNode = static_cast<node*>(parent.internalPointer());
    const auto& children = parentNode->getChildren();
    if (row >= children.size()) {return QModelIndex();}

    node* childNode = children[row];
    return createIndex(row, column, childNode);
}

3. parent方法中获取父节点行号的逻辑错误

你调用row(parentNode)来获取父节点在其自身父节点中的行号,但QAbstractItemModel没有接收node*参数的row方法,需自定义辅助函数实现节点行号查找。

首先在TreeModel类中添加私有辅助函数:

private:
    int getNodeRow(node* n) const {
        if (!n || !n->getParent()) {
            return 0; // 根节点行号固定为0
        }
        const auto& siblings = n->getParent()->getChildren();
        auto it = std::find(siblings.begin(), siblings.end(), n);
        return it != siblings.end() ? std::distance(siblings.begin(), it) : -1;
    }

然后修改parent方法:

QModelIndex TreeModel::parent(const QModelIndex& index) const {
    if (!index.isValid()) {return QModelIndex();}

    node* n = static_cast<node*>(index.internalPointer());
    node* parentNode = n->getParent();
    if (!parentNode) {return QModelIndex();} // 根节点无父节点

    int parentRow = getNodeRow(parentNode);
    if (parentRow == -1) {return QModelIndex();}

    return createIndex(parentRow, 0, parentNode);
}

4. data方法未处理Qt::DisplayRole

当前data仅处理图标(Qt::DecorationRole),未处理显示文本(Qt::DisplayRole),导致视图无有效内容显示,出现的‘1’是视图异常占位符。需添加文本返回逻辑:

修改后代码:

QVariant TreeModel::data(const QModelIndex &index, int role) const {
    if (!index.isValid()) {return QVariant();}

    node* n = static_cast<node*>(index.internalPointer());
    if (role == Qt::DecorationRole) {
        if (index.column() == 0) {
            QPixmap pixmap(16, 16);
            pixmap.fill(Qt::black);
            QPainter painter(&pixmap);
            painter.setBrush(Qt::white);
            painter.drawRect(0, 0, 15, 15);
            return QIcon(pixmap);
        }
        return QVariant();
    } else if (role == Qt::DisplayRole) {
        // 替换为你的node实际显示文本,比如患者姓名
        // 示例:return QString::fromStdString(n->getPatient()->getName());
        return QString("家族成员");
    }
    return QVariant();
}

5. hasChildren方法顶层节点逻辑优化

当前hasChildren在父索引无效时直接返回true,会导致视图错误显示展开箭头(即使根节点无子女),需修改为判断根节点是否有子节点:

修改后代码:

bool TreeModel::hasChildren(const QModelIndex& parent) const {
    if (!parent.isValid()) {
        // 顶层节点为根节点,判断其是否有子节点
        return !ft_.get_root()->getChildren().empty();
    }
    node* n = static_cast<node*>(parent.internalPointer());
    return !n->getChildren().empty();
}

额外检查项

  • 确认TreeModel构造函数中ft_正确持有Family_tree的树形结构,避免拷贝构造导致的节点指针失效。
  • 验证node类的getParent()、getChildren()方法返回值正确,无空指针或空列表错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 11:35:22