LINUX.ORG.RU

Как правильно удалять данные из модели данных Qt?

 ,


0

1

Есть некоторые данные в таком виде

QList <Task> tasks;

Модель для этих данных

// taskmodel.h
#ifndef TASKSMODEL_H
#define TASKSMODEL_H

#include <QAbstractListModel>
#include "def.h"

// реализация модели задач

class TasksModel : public QAbstractListModel
{
    Q_OBJECT
    QList <Task> tasks;
public:
    explicit TasksModel(QObject *parent = 0);

    int rowCount(const QModelIndex &parent = QModelIndex()) const;
    QVariant data(const QModelIndex &index, int role) const;

    void resetData(const QList<Task> &taskslist);

    Task getItem(const QModelIndex &index);
    
signals:
    
public slots:
    
};

#endif // TASKSMODEL_H

// taskmodel.cpp
#include "tasksmodel.h"

TasksModel::TasksModel(QObject *parent) :
    QAbstractListModel(parent)
{
}

int TasksModel::rowCount(const QModelIndex &parent) const
{
    return this->tasks.count();
}

QVariant TasksModel::data(const QModelIndex &index, int role) const
{
    // проверяем на валидность и на выход из диапазона
    if(!index.isValid() or index.row() >= this->tasks.count())
        return QVariant();

    // возвращаем то, что нужно
    switch(role){
    case Qt::DisplayRole:
        return this->tasks.at(index.row()).title;
        break;

    case Qt::ToolTipRole:
        return this->tasks.at(index.row()).details;
        break;

    default:
        return QVariant();
        break;
    }
}

void TasksModel::resetData(const QList<Task> &taskslist)
{
    this->beginResetModel();
    this->tasks.clear();
    this->tasks = taskslist;
    this->endResetModel();
}

Task TasksModel::getItem(const QModelIndex &index)
{
    return this->tasks.at(index.row());
}

и к ней прокси модель для отображения на QListView с фильтром по дате

// taskproxymodel.h
#ifndef TASKSPROXYMODEL_H
#define TASKSPROXYMODEL_H

#include <QSortFilterProxyModel>
#include <QDate>
#include "tasksmodel.h"
#include "def.h"
#include <QDebug>

class TasksProxyModel : public QSortFilterProxyModel
{
    QDate filter;
public:
    TasksProxyModel();
    void setFilter(const QDate &filter);
    const QDate getFilter() const;

protected:
    bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
};

#endif // TASKSPROXYMODEL_H

// taskproxymodel.cpp
#include "tasksproxymodel.h"

TasksProxyModel::TasksProxyModel()
{
}

void TasksProxyModel::setFilter(const QDate &filter)
{
    this->filter = filter;
    this->filterChanged();
}

const QDate TasksProxyModel::getFilter() const
{
    return this->filter;
}

bool TasksProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
    TasksModel *model = (TasksModel *)this->sourceModel();
    Task rec = model->getItem(model->index(source_row, 0, source_parent));
    // если подходит под фильтр, то true
    return rec.date == this->filter ? true : false;
}

Собственно вопрос: как же правильно удалить одну запись из списка, из модели и из проксимодели? пробовал вот так

    // получаем индекс элемента в исходной модели
    QModelIndex index = this->tasksProxyModel.mapToSource(this->ui->lv_tasks->currentIndex());
    // удаляем элемент из прокси модели
    this->tasksProxyModel.removeRow(this->ui->lv_tasks->currentIndex().row());
    // удаляем элемент из исходной модели
    this->tasksModel.removeRow(index.row());
    // удаляем элемент из списка по полученному индексу
    this->tasks.removeAt(index.row());
но из списка QListView не исчезает. зато работает вот так
    // получаем индекс элемента в исходной модели
    QModelIndex index = this->tasksProxyModel.mapToSource(this->ui->lv_tasks->currentIndex());
    // удаляем элемент из списка по полученному индексу
    this->tasks.removeAt(index.row());
    this->tasksModel.resetData(this->tasks);
но не думаю, что это хорошее решение, особенно если записей много, перестраивать модель заново каждый раз после удаления чего нибудь

★★★★

Перед обновлением модель как минимум должна выпускать сигнал aboutToChangeLayout, а как максимум — выпускать сигнал об изменении определённых строк и колонок. После обновления как минимум сигнал layoutChanged, как максимум — сигнал об изменении определённых строк и колонок.

quiet_readonly ★★★★ ()
Ответ на: комментарий от panter_dsd

думал без этого обойтись, ведь мне всего 1 строку удалять надо, заглянул в исходники, а removeRow дергает

removeRows(arow, 1, aparent);
так что видимо на нем все завязано и видимо придется переопределить.

WRG ★★★★ ()
Последнее исправление: WRG (всего исправлений: 1)
Ответ на: комментарий от WRG

И insertRows тоже можно определить.

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

panter_dsd ★★★★ ()
Ответ на: комментарий от WRG

так что видимо на нем все завязано и видимо придется переопределить.

а ты глянь как у меня реализовано.

MikeDM ★★★★★ ()

В таком простом случае можно было бы обойтись и QStandardItemModel.

unC0Rr ★★★★★ ()
Ответ на: комментарий от MikeDM

вроде разобрался. даже deleteRows переопределять не пришлось.

WRG ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.