Поиск / удаление строки из QStandardItemModel по данным элемента - PullRequest
2 голосов
/ 01 июля 2019

У меня есть QStandardItemModel с одним столбцом (представляет список).Каждый элемент в списке имеет уникальный целочисленный идентификатор, сохраняемый как данные QStandardItem (через QStandardItem::setData, который, я думаю, входит в Qt::UserRole+1 по умолчанию).

Учитывая один из этих идентификаторов, я 'Я хотел бы найти и удалить соответствующую строку из модели.Прямо сейчас я делаю это:

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;
        }
    }

}

Это работает отлично, но каждая строка этой функции заставляет меня съеживаться.Есть ли более чистый способ сделать это?

Ответы [ 3 ]

4 голосов
/ 01 июля 2019

Как насчет обхода 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

Возвращает 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);
2 голосов
/ 01 июля 2019

Вам нужно получить индекс строки из вашего идентификатора элемента.

Более эффективным способом может быть использование QMap с индексом строки в качестве значения и идентификатором элемента в качестве ключа.

В этом случае вам также необходимо поддерживать значения карты каждый раз, когда вы добавляете / удаляете строку.

Если в вашем списке нет 3 миллионов элементов, просто сохраняйте его простым и используйте свой код. Оптимизируя этот код, вы, вероятно, также добавите сложность и уменьшите удобство обслуживания, и получите 0,05 мс вместо 0,06 мс.

В коде GUI у меня часто есть такой код: он прост, все сразу получают его, и он делает свою работу. Это также достаточно быстро.

1 голос
/ 03 июля 2019

Вы используете findItems неправильно, он уже может вернуть нужный элемент, просто передав значение, которое вы ищете. Если вы называете это так, как вы делаете сейчас, вы просматриваете свои элементы как минимум два раза, так как findItems должен перебрать все элементы, чтобы найти те, которые соответствуют вашему шаблону, в вашем случае все элементы соответствуют, тогда вы итерация возвращенных предметов снова, чтобы найти 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 возвращает сразу после того, как найдено количество элементов, соответствующих шаблону, в этом случае значение sessionId, поэтому он не всегда повторяет все элементы; это более эффективно. Очевидно, что если значение не найдено после итерации всех элементов, возвращается пустой список.

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);
}
...