QAbstractItemModel + QTreeView 什么会导致项目变得不可选择?

发布于 2024-12-05 02:59:29 字数 12182 浏览 7 评论 0原文

我正在尝试基于 QAbstractItemModel 创建自己的模型。看起来效果很好。它通过了模型测试断言。

当我删除一行时,我遇到了这个奇怪的问题。删除操作正常。 但随后其他行变得不可选择(并非全部)。您遇到过这样的行为吗?

在什么情况下QTreeView可以决定该行不能被选择?

有什么想法吗?如果需要,我可以提供整个模型的实现。


编辑:作为替代方案,我正在寻找 100% 工作 QAbstractItemModel + QtSql + QTreeView 实现的示例。模型应提供添加和删除方法,并且必须通过模型测试。 这也可以回答我的问题:-)


编辑:下面是我的源代码。压缩一点以使其更小

ps 我现在看到parent() 实现中有一个错误。删除一行后 nodeParams[*].row 中的值包含不正确的位置。如何在不将整个树加载到内存中的情况下解决这个问题?

class TasksModel : public QAbstractItemModel
{
    Q_OBJECT
public:
    explicit TasksModel(QObject *parent = 0);

    virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
    virtual Qt::ItemFlags flags ( const QModelIndex & index ) const;
    virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
    virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
    virtual int rowCount (const QModelIndex & parent = QModelIndex() ) const;
    virtual bool hasChildren ( const QModelIndex & parent = QModelIndex() ) const;
    virtual void sort ( int column, Qt::SortOrder order = Qt::AscendingOrder );
    virtual QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
    virtual QModelIndex parent ( const QModelIndex & index ) const;
    virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole );
    virtual bool setHeaderData ( int section, Qt::Orientation orientation, const QVariant & value, int role = Qt::EditRole );
    int selectedId;
    QModelIndex indexForId(int id);

    // add,remove..
    int addTask(QMap<QString,QVariant> params);
    void removeTask(int id, bool children);

private:
    int nrOfColumns;
    QSqlDatabase* dbh;

    mutable QMap<qint64, QSqlQuery*> subQueries;
    mutable QMap<qint64, int> rowsCount;
    mutable QSqlQuery topQuery;
    mutable int topRowsCount;
    mutable bool topQueryReady;
    QSqlQuery* verifyAndPrepareQuery (const QModelIndex& index) const;
    int totalCount(const qint64 id, bool force=false) const;
    void recountTotalCount(const qint64 id) const;

    struct NodeParams {
        int row;
        int parentId;
    };
    mutable QMap<qint64, NodeParams> nodeParams;

signals:

public slots:

};

// ------------------ implementation ---------------------------


TasksModel::TasksModel(QObject *parent) : QAbstractItemModel(parent)
{
    nrOfColumns = 2;

    topQueryReady = false;
    topRowsFetched = 0;
    topRowsCount = 0;
    selectedId = 0;

    // db connection
    dbh = Config::connection();
}


QVariant TasksModel::data ( const QModelIndex & index, int role ) const
{
    if (!index.isValid()) return QVariant();
    int column = index.column();

    if (role == Qt::DisplayRole || role == Qt::EditRole)
    {
        QSqlQuery* query = verifyAndPrepareQuery(index.parent());
        if (!query->seek(index.row())) return QVariant("x");
        switch (column)
        {
            case 0: return query->value(2).toString();
            case 1: return query->value(4).toString() +"%";
        }
    }
    else if (role == Qt::CheckStateRole) {
        // set status of checkbox in 2nd column
        if (column == 1) {

            QSqlQuery* query = verifyAndPrepareQuery(index.parent());
            if (!query->seek(index.row())) return QVariant();

            if (query->value(3).toInt() > 0)
                return Qt::Checked;
            else
                return Qt::Unchecked;
        }
    }
    else if (role == Qt::TextAlignmentRole) {
        switch (column)
        {
            case 0: return Qt::AlignLeft + Qt::AlignVCenter;
            case 1: return Qt::AlignRight + Qt::AlignVCenter;
        }
    }

    return QVariant();

}

Qt::ItemFlags TasksModel::flags ( const QModelIndex & index ) const
{
    if (!index.isValid()) return 0;

    Qt::ItemFlags result = Qt::ItemIsEnabled | Qt::ItemIsSelectable;

    if (index.column()==0) {
        result |= Qt::ItemIsEditable;
    }
    else if (index.column()==1) {
        result |= Qt::ItemIsUserCheckable;
    }

    return result;
}

QVariant TasksModel::headerData ( int section, Qt::Orientation orientation, int role) const
{
    return QVariant();
}

int TasksModel::columnCount ( const QModelIndex & parent ) const
{
    return nrOfColumns;
}


int TasksModel::rowCount (const QModelIndex & parent) const
{
    if (parent.isValid() && parent.column() != 0)
        return 0;

    int id;
    if (parent.isValid())
        id = parent.internalId();
    else
        id = 0;

    return totalCount(id);
}


bool TasksModel::hasChildren ( const QModelIndex & parent) const
{
    if (parent.isValid()) {
        if (totalCount(parent.internalId()) > 0) return true;
    } else {
        if (totalCount(0) > 0) return true;
    }

    return false;
}


void TasksModel::sort ( int column, Qt::SortOrder order )
{
}



// TreeView methods
QModelIndex TasksModel::index ( int row, int column, const QModelIndex& parent ) const
{
    if (row < 0 || column < 0 || column >= nrOfColumns)
            // || (parent.isValid() && parent.column() != 0))
        return QModelIndex();

    QSqlQuery* query = verifyAndPrepareQuery(parent);

    if (!query->seek(row)) return QModelIndex();
    int id = query->value(0).toInt();

    if (!nodeParams.contains(id)) {
        NodeParams params;
        params.parentId = (int)query->value(1).toInt();
        params.row = row;
        nodeParams.insert(id, params);
    }

    return QAbstractItemModel::createIndex(row, column, id);
}

QModelIndex TasksModel::parent ( const QModelIndex & index ) const
{
    return QModelIndex();

    if (!index.isValid()) { return QModelIndex(); }
    if (!nodeParams.contains(index.internalId())) { qDebug("b"); return QModelIndex();}

    NodeParams itemParams = nodeParams.value(index.internalId());

    if (itemParams.parentId == 0) return QModelIndex();
    if (!nodeParams.contains(itemParams.parentId)) { qDebug("d"); return QModelIndex(); }

    NodeParams parentParams = nodeParams.value(itemParams.parentId);

    int parentId = itemParams.parentId;
    int parentRow = parentParams.row;

    return QAbstractItemModel::createIndex(parentRow, 0, parentId);

}


// Edit methods
bool TasksModel::setData ( const QModelIndex & index, const QVariant & value, int role )
{
    return false;
}

bool TasksModel::setHeaderData ( int section, Qt::Orientation orientation, const QVariant & value, int role )
{
    return false;
}


// Build and return query object for current index parent
QSqlQuery* TasksModel::verifyAndPrepareQuery (const QModelIndex& index) const
{
    if (!index.isValid()) {
        // prepare query for root
        if (!topQueryReady) {
            QString sql = "SELECT id,id_parent,title,complete,completion_rate,priority,date_start,date_deadline,date_preferred FROM tasks WHERE id_parent = 0";
            topQuery = QSqlQuery(sql, *dbh);
            topRowsFetched = 0;
            topRowsCount = 0;
            topQueryReady = true;
        }
        return &topQuery;

    } else {
        // prepare queries for subitems (queries stored in subQueries QMap)
        qint64 id = index.internalId();
        if (!subQueries.contains(id)) {
            QString sql = "SELECT id,id_parent,title,complete,completion_rate,priority,date_start,date_deadline,date_preferred FROM tasks WHERE id_parent = "+ QString::number(id);
            QSqlQuery* querySub = new QSqlQuery(sql, *dbh);

            subQueries.insert(id, querySub);
            rowsFetched.insert(id, 0);
            return querySub;
        }
        return subQueries.value(id);
    }

}

int TasksModel::totalCount(const qint64 id, bool force) const
{
    force = true; // temporary setting, to force recalculation in each request, to be optimized
    if (id > 0) {
        if (!rowsCount.contains(id) || force) {
            QString sql = "SELECT COUNT(*) FROM tasks WHERE id_parent = "+ QString::number(id);
            QSqlQuery countQuery(sql, *dbh);
            countQuery.next();
            int count = countQuery.value(0).toInt();

            rowsCount[id] = count;
            return count;
        }
        return rowsCount.value(id);
    } else {
        if (topRowsCount == 0 || force) {
            QString sql = "SELECT COUNT(*) FROM tasks WHERE id_parent = 0 ";
            QSqlQuery countQuery(sql, *dbh);
            countQuery.next();
            topRowsCount = countQuery.value(0).toInt();
        }

        return topRowsCount;
    }
}

void TasksModel::recountTotalCount(const qint64 id) const
{
    // reset variables related to rowsCount and data functions. Called after new child is created or removed
    if (id > 0) {
        rowsCount.remove(id);
        subQueries.remove(id);
    }
    else {
        topRowsCount = 0;
        topQueryReady = false;
    }
    totalCount(id);
}

QModelIndex TasksModel::indexForId(int id)
{
    // convert id to index based on data stored in nodeParams
    if (id == 0) return QModelIndex();
    if (!nodeParams.contains(id)) { qDebug() << "z"; return QModelIndex(); }

    NodeParams params = nodeParams.value(id);
    return QAbstractItemModel::createIndex(params.row, 0, id);
}



// CRUD
int TasksModel::addTask(QMap<QString,QVariant> params)
{
    // create record
    QString sql;

    if (params.value("complete").toInt() == 1)
        params["completion_rate"] = 100;

    // Add task
    QSqlQuery query(*dbh);
    sql = "INSERT INTO tasks (id_parent,id_sibling,position,title,description,complete,completion_rate,priority,date_start,date_deadline,date_preferred) VALUES (?,?,?,?,?,?,?,?,?,?,?)";
    query.prepare(sql);
    query.addBindValue(params.value("id_parent",        0));
    query.addBindValue(params.value("id_sibling",       0));
    query.addBindValue(params.value("position",         0));
    query.addBindValue(params.value("title",            ""));
    query.addBindValue(params.value("description",      ""));
    query.addBindValue(params.value("complete",         0));
    query.addBindValue(params.value("completion_rate",  0));
    query.addBindValue(params.value("priority",         0));
    query.addBindValue(params.value("date_start",       0));
    query.addBindValue(params.value("date_deadline",    0));
    query.addBindValue(params.value("date_preferred",   0));

    // begin insert
    int parentId = params.value("id_parent").toInt();
    int count = totalCount(parentId);
    beginInsertRows(indexForId(parentId), count, count);

    query.exec();
    int taskId = query.lastInsertId().toInt();

    // update nodeParams map
    NodeParams subNodeParams;
    subNodeParams.row = count;
    subNodeParams.parentId = parentId;
    nodeParams[taskId] = subNodeParams;

    recountTotalCount(parentId);
    verifyAndPrepareQuery(indexForId(parentId));
    endInsertRows();
    // insert finished

    return taskId;
}


// method recursively removes task and its children
void TasksModel::removeTask(int id, bool children)
{
    if (!nodeParams.contains(id)) return; 
    NodeParams taskParams = nodeParams.value(id);

    QString sql;
    QSqlQuery query(*dbh);

    // remove children
    if (children) {
        sql = "SELECT id FROM tasks WHERE id_parent = "+ QString::number(id);
        QSqlQuery query2(sql, *dbh);
        while (query2.next()) {
            removeTask(query2.value(0).toInt(), true);
        }
    }

    // remove task (tasks)
    beginRemoveRows(indexForId(taskParams.parentId), taskParams.row, taskParams.row);

    sql = "DELETE FROM tasks WHERE id = "+ QString::number(id);
    query.exec(sql);

    // update ui
    recountTotalCount(taskParams.parentId);
    endRemoveRows();
    nodeParams.remove(id);

    // remove task (tasks_parents)
    sql = "DELETE FROM tasks_parents WHERE id_task = "+ QString::number(id) +" AND id_parent = "+ QString::number(taskParams.parentId);
    query.exec(sql);

    verifyAndPrepareQuery(indexForId(taskParams.parentId));

}

I'm trying to create my own model based on QAbstractItemModel. It seems to work fine. It passes modeltest assertions.

I've this strange problem when I remove a row. Removal operation works ok.
But then other rows become unselectable (not all of them). Have You ever come across such behaviour ?

In which conditions QTreeView could decide that row can not be selected ?

Any ideas ? If needed I can provide the whole model implementation.


EDIT: As an alternative I'm looking for an example of 100% working QAbstractItemModel + QtSql + QTreeView implementation. Model should provide add and remove methods and it has to pass modeltest.
This also would answer my question :-)


EDIT: Below is my source code. Compacted a little to make it smaller

ps I see now that there is a bug in parent() implementation. After removing a row
values in nodeParams[*].row contain incorrect positions. How do You solve this issue without loading the whole tree into memory ?

class TasksModel : public QAbstractItemModel
{
    Q_OBJECT
public:
    explicit TasksModel(QObject *parent = 0);

    virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
    virtual Qt::ItemFlags flags ( const QModelIndex & index ) const;
    virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
    virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
    virtual int rowCount (const QModelIndex & parent = QModelIndex() ) const;
    virtual bool hasChildren ( const QModelIndex & parent = QModelIndex() ) const;
    virtual void sort ( int column, Qt::SortOrder order = Qt::AscendingOrder );
    virtual QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
    virtual QModelIndex parent ( const QModelIndex & index ) const;
    virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole );
    virtual bool setHeaderData ( int section, Qt::Orientation orientation, const QVariant & value, int role = Qt::EditRole );
    int selectedId;
    QModelIndex indexForId(int id);

    // add,remove..
    int addTask(QMap<QString,QVariant> params);
    void removeTask(int id, bool children);

private:
    int nrOfColumns;
    QSqlDatabase* dbh;

    mutable QMap<qint64, QSqlQuery*> subQueries;
    mutable QMap<qint64, int> rowsCount;
    mutable QSqlQuery topQuery;
    mutable int topRowsCount;
    mutable bool topQueryReady;
    QSqlQuery* verifyAndPrepareQuery (const QModelIndex& index) const;
    int totalCount(const qint64 id, bool force=false) const;
    void recountTotalCount(const qint64 id) const;

    struct NodeParams {
        int row;
        int parentId;
    };
    mutable QMap<qint64, NodeParams> nodeParams;

signals:

public slots:

};

// ------------------ implementation ---------------------------


TasksModel::TasksModel(QObject *parent) : QAbstractItemModel(parent)
{
    nrOfColumns = 2;

    topQueryReady = false;
    topRowsFetched = 0;
    topRowsCount = 0;
    selectedId = 0;

    // db connection
    dbh = Config::connection();
}


QVariant TasksModel::data ( const QModelIndex & index, int role ) const
{
    if (!index.isValid()) return QVariant();
    int column = index.column();

    if (role == Qt::DisplayRole || role == Qt::EditRole)
    {
        QSqlQuery* query = verifyAndPrepareQuery(index.parent());
        if (!query->seek(index.row())) return QVariant("x");
        switch (column)
        {
            case 0: return query->value(2).toString();
            case 1: return query->value(4).toString() +"%";
        }
    }
    else if (role == Qt::CheckStateRole) {
        // set status of checkbox in 2nd column
        if (column == 1) {

            QSqlQuery* query = verifyAndPrepareQuery(index.parent());
            if (!query->seek(index.row())) return QVariant();

            if (query->value(3).toInt() > 0)
                return Qt::Checked;
            else
                return Qt::Unchecked;
        }
    }
    else if (role == Qt::TextAlignmentRole) {
        switch (column)
        {
            case 0: return Qt::AlignLeft + Qt::AlignVCenter;
            case 1: return Qt::AlignRight + Qt::AlignVCenter;
        }
    }

    return QVariant();

}

Qt::ItemFlags TasksModel::flags ( const QModelIndex & index ) const
{
    if (!index.isValid()) return 0;

    Qt::ItemFlags result = Qt::ItemIsEnabled | Qt::ItemIsSelectable;

    if (index.column()==0) {
        result |= Qt::ItemIsEditable;
    }
    else if (index.column()==1) {
        result |= Qt::ItemIsUserCheckable;
    }

    return result;
}

QVariant TasksModel::headerData ( int section, Qt::Orientation orientation, int role) const
{
    return QVariant();
}

int TasksModel::columnCount ( const QModelIndex & parent ) const
{
    return nrOfColumns;
}


int TasksModel::rowCount (const QModelIndex & parent) const
{
    if (parent.isValid() && parent.column() != 0)
        return 0;

    int id;
    if (parent.isValid())
        id = parent.internalId();
    else
        id = 0;

    return totalCount(id);
}


bool TasksModel::hasChildren ( const QModelIndex & parent) const
{
    if (parent.isValid()) {
        if (totalCount(parent.internalId()) > 0) return true;
    } else {
        if (totalCount(0) > 0) return true;
    }

    return false;
}


void TasksModel::sort ( int column, Qt::SortOrder order )
{
}



// TreeView methods
QModelIndex TasksModel::index ( int row, int column, const QModelIndex& parent ) const
{
    if (row < 0 || column < 0 || column >= nrOfColumns)
            // || (parent.isValid() && parent.column() != 0))
        return QModelIndex();

    QSqlQuery* query = verifyAndPrepareQuery(parent);

    if (!query->seek(row)) return QModelIndex();
    int id = query->value(0).toInt();

    if (!nodeParams.contains(id)) {
        NodeParams params;
        params.parentId = (int)query->value(1).toInt();
        params.row = row;
        nodeParams.insert(id, params);
    }

    return QAbstractItemModel::createIndex(row, column, id);
}

QModelIndex TasksModel::parent ( const QModelIndex & index ) const
{
    return QModelIndex();

    if (!index.isValid()) { return QModelIndex(); }
    if (!nodeParams.contains(index.internalId())) { qDebug("b"); return QModelIndex();}

    NodeParams itemParams = nodeParams.value(index.internalId());

    if (itemParams.parentId == 0) return QModelIndex();
    if (!nodeParams.contains(itemParams.parentId)) { qDebug("d"); return QModelIndex(); }

    NodeParams parentParams = nodeParams.value(itemParams.parentId);

    int parentId = itemParams.parentId;
    int parentRow = parentParams.row;

    return QAbstractItemModel::createIndex(parentRow, 0, parentId);

}


// Edit methods
bool TasksModel::setData ( const QModelIndex & index, const QVariant & value, int role )
{
    return false;
}

bool TasksModel::setHeaderData ( int section, Qt::Orientation orientation, const QVariant & value, int role )
{
    return false;
}


// Build and return query object for current index parent
QSqlQuery* TasksModel::verifyAndPrepareQuery (const QModelIndex& index) const
{
    if (!index.isValid()) {
        // prepare query for root
        if (!topQueryReady) {
            QString sql = "SELECT id,id_parent,title,complete,completion_rate,priority,date_start,date_deadline,date_preferred FROM tasks WHERE id_parent = 0";
            topQuery = QSqlQuery(sql, *dbh);
            topRowsFetched = 0;
            topRowsCount = 0;
            topQueryReady = true;
        }
        return &topQuery;

    } else {
        // prepare queries for subitems (queries stored in subQueries QMap)
        qint64 id = index.internalId();
        if (!subQueries.contains(id)) {
            QString sql = "SELECT id,id_parent,title,complete,completion_rate,priority,date_start,date_deadline,date_preferred FROM tasks WHERE id_parent = "+ QString::number(id);
            QSqlQuery* querySub = new QSqlQuery(sql, *dbh);

            subQueries.insert(id, querySub);
            rowsFetched.insert(id, 0);
            return querySub;
        }
        return subQueries.value(id);
    }

}

int TasksModel::totalCount(const qint64 id, bool force) const
{
    force = true; // temporary setting, to force recalculation in each request, to be optimized
    if (id > 0) {
        if (!rowsCount.contains(id) || force) {
            QString sql = "SELECT COUNT(*) FROM tasks WHERE id_parent = "+ QString::number(id);
            QSqlQuery countQuery(sql, *dbh);
            countQuery.next();
            int count = countQuery.value(0).toInt();

            rowsCount[id] = count;
            return count;
        }
        return rowsCount.value(id);
    } else {
        if (topRowsCount == 0 || force) {
            QString sql = "SELECT COUNT(*) FROM tasks WHERE id_parent = 0 ";
            QSqlQuery countQuery(sql, *dbh);
            countQuery.next();
            topRowsCount = countQuery.value(0).toInt();
        }

        return topRowsCount;
    }
}

void TasksModel::recountTotalCount(const qint64 id) const
{
    // reset variables related to rowsCount and data functions. Called after new child is created or removed
    if (id > 0) {
        rowsCount.remove(id);
        subQueries.remove(id);
    }
    else {
        topRowsCount = 0;
        topQueryReady = false;
    }
    totalCount(id);
}

QModelIndex TasksModel::indexForId(int id)
{
    // convert id to index based on data stored in nodeParams
    if (id == 0) return QModelIndex();
    if (!nodeParams.contains(id)) { qDebug() << "z"; return QModelIndex(); }

    NodeParams params = nodeParams.value(id);
    return QAbstractItemModel::createIndex(params.row, 0, id);
}



// CRUD
int TasksModel::addTask(QMap<QString,QVariant> params)
{
    // create record
    QString sql;

    if (params.value("complete").toInt() == 1)
        params["completion_rate"] = 100;

    // Add task
    QSqlQuery query(*dbh);
    sql = "INSERT INTO tasks (id_parent,id_sibling,position,title,description,complete,completion_rate,priority,date_start,date_deadline,date_preferred) VALUES (?,?,?,?,?,?,?,?,?,?,?)";
    query.prepare(sql);
    query.addBindValue(params.value("id_parent",        0));
    query.addBindValue(params.value("id_sibling",       0));
    query.addBindValue(params.value("position",         0));
    query.addBindValue(params.value("title",            ""));
    query.addBindValue(params.value("description",      ""));
    query.addBindValue(params.value("complete",         0));
    query.addBindValue(params.value("completion_rate",  0));
    query.addBindValue(params.value("priority",         0));
    query.addBindValue(params.value("date_start",       0));
    query.addBindValue(params.value("date_deadline",    0));
    query.addBindValue(params.value("date_preferred",   0));

    // begin insert
    int parentId = params.value("id_parent").toInt();
    int count = totalCount(parentId);
    beginInsertRows(indexForId(parentId), count, count);

    query.exec();
    int taskId = query.lastInsertId().toInt();

    // update nodeParams map
    NodeParams subNodeParams;
    subNodeParams.row = count;
    subNodeParams.parentId = parentId;
    nodeParams[taskId] = subNodeParams;

    recountTotalCount(parentId);
    verifyAndPrepareQuery(indexForId(parentId));
    endInsertRows();
    // insert finished

    return taskId;
}


// method recursively removes task and its children
void TasksModel::removeTask(int id, bool children)
{
    if (!nodeParams.contains(id)) return; 
    NodeParams taskParams = nodeParams.value(id);

    QString sql;
    QSqlQuery query(*dbh);

    // remove children
    if (children) {
        sql = "SELECT id FROM tasks WHERE id_parent = "+ QString::number(id);
        QSqlQuery query2(sql, *dbh);
        while (query2.next()) {
            removeTask(query2.value(0).toInt(), true);
        }
    }

    // remove task (tasks)
    beginRemoveRows(indexForId(taskParams.parentId), taskParams.row, taskParams.row);

    sql = "DELETE FROM tasks WHERE id = "+ QString::number(id);
    query.exec(sql);

    // update ui
    recountTotalCount(taskParams.parentId);
    endRemoveRows();
    nodeParams.remove(id);

    // remove task (tasks_parents)
    sql = "DELETE FROM tasks_parents WHERE id_task = "+ QString::number(id) +" AND id_parent = "+ QString::number(taskParams.parentId);
    query.exec(sql);

    verifyAndPrepareQuery(indexForId(taskParams.parentId));

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

埋情葬爱 2024-12-12 02:59:29

查看模型的源代码会很有帮助,

如果没有这个,我将从检查 QAbstractItemModel 开始::flags 方法正在返回您无法选择的项目

looking at the model's source code would be helpful,

without this I would start from checking what QAbstractItemModel::flags method is returning for items which you can't select

︶葆Ⅱㄣ 2024-12-12 02:59:29

您的 nodeParams 必须始终保持最新。这意味着每次添加和删除后,您必须重新加载受影响父项的所有子项的条目。

简单地延迟加载树作为项目不是更好吗?创建额外的类,例如。 TreeItem 并将子项存储在 QList 子项中。

Your nodeParams always has to stay up to date. This means that after each add and remove you have to reload entries of all children of a parent that has been affected.

Wouldn't it be better to simply lazy load tree as items ? Create additional class eg. TreeItem and store children inside QList children.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文