通过项目数据从 QStandardItemModel 中查找/删除一行

Finding / removing a row from a QStandardItemModel by item data

我有一个只有一列的 QStandardItemModel(代表一个列表)。列表中的每个项目都有一个唯一的整数 ID,存储为 QStandardItem 的数据(通过 QStandardItem::setData,我猜默认情况下是 Qt::UserRole+1)。

给定这些 ID 之一,我想从模型中找到并删除相应的行。现在我正在这样做:

void NetworkManager::removeSessionFromModel (QStandardItemModel *model, int sessionId) {

    foreach (const QStandardItem *item, model->findItems("*", Qt::MatchWildcard)) {
        if (item->data() == sessionId) {
            model->removeRow(item->index().row());
            break;
        }
    }

}

它工作正常,但该函数的每一行都让我感到畏缩。有没有更简洁的方法来执行这些操作?

您需要从项目 ID 中获取行索引。

一种更有效的方法可能是使用 QMap,其中行索引作为值,项目 ID 作为键。

在这种情况下,您还需要在每次 add/remove 行时维护地图值。

如果您的列表中没有 300 万个项目,请保持简单并使用您的代码。 通过优化此代码,您可能还会增加复杂性并降低可维护性,并且您得到的是 0.05 毫秒而不是 0.06 毫秒。

在 GUI 代码中,我经常有这样的代码:它很简单,每个人都能立即理解并完成工作。它也足够快。

直接遍历QStandardItemModel怎么样?像这样:

void NetworkManager::removeSessionFromModel (QStandardItemModel *model, int sessionId) 
{
    for (int i = 0; i < model->rowCount(); ++i)
    {
        if (model->item(i)->data() == sessionId)
        {
            model->removeRow(i);
            break;
        }
    } 
}

不确定 QStandardItemModel 如何处理随机访问,也许您的方法更有效。

编辑:

其实有一个函数可以为所欲为:QAbstractItemModel::match

它 returns QModelIndexList 包含在给定角色中具有匹配数据的所有条目。

void NetworkManager::removeSessionFromModel (QStandardItemModel *model, int sessionId)
{
    QModelIndexList list = model->match(model->index(0, 0), Qt::UserRole + 1, sessionId);

    if (!list.empty())
        model->removeRow(list .first().row());
}

将数据设置到特定角色可以按如下方式完成:

model->setData(model->index(row, col), QVariant(13), Qt::UserRole + 1);

你使用的findItems错了,它已经可以return你想要的项目,只需传递你要搜索的值。如果您像现在这样称呼它,那么您至少要遍历您的项目两次,因为 findItems 必须遍历所有项目以找到与您的模式匹配的项目,在您的情况下,所有项目都匹配,然后您再次迭代 returned 项目以找到 sessionId.

void NetworkManager::removeSessionFromModel (QStandardItemModel *model, int sessionId) {

    auto items = model->findItems(QString::number(sessionId));
    if (!items.empty()) {
        auto row = items.first()->index().row();
        model->removeRow(row);
    }
}

或者您可以使用 match 方法,因为 findItems 在内部使用它,所以您避免分配 StandardItem 只是为了获取它的索引。另外 match returns 紧跟在与模式匹配的项目数之后,在本例中是 sessionId 的值,因此它并不总是迭代所有项目;这样更有效率。显然,如果在迭代所有项目后未找到该值,则它 return 是一个空列表。

auto start = model->index(0, 0);
auto indexes = model->match(start, Qt::UserRole + 1, QString::number(sessionId), 1, Qt::MatchExactly);
if (!indexes.empty()) {
    auto row = indexes.first().row();
    model->removeRow(row);
}