Как мне синхронизировать мой QAbstractTableModel с моим хранилищем данных? - PullRequest
4 голосов
/ 03 мая 2011

В моем приложении есть класс для хранения списка предметов:

class Database : public QObject
{
    Q_OBJECT

public:
    Database(QObject *parent, const QString &name);

    const Entry& item(int idx) const { Q_ASSERT(idx < itemCount()); return _items.at(idx); }
    const QString& name() const { return _name; }
    int itemCount() const { return _items.size(); }

    bool addItem(const Entry &item);
    bool addItems(const Database *source, const QList<int> &idxs);
    bool updateItem(int idx, const Entry &updated);
    void removeItem(int idx);
    void removeItems(const QList<int> &idxs);

private:
    QList<Entry> _items;

signals:
    void itemsRemoved(int start, int count);
    void itemsAdded(int count);
    void itemChanged(int index);
    void countUpdate();
};

Функции манипуляции с предметами (добавление, обновление, удаление) выдают соответствующие сигналы, когда выполнено (элементы добавлены, изменены, удалены). У меня есть список таких баз данных и QTableView для отображения их содержимого. У меня также есть один объект пользовательского класса, производный от класса QAbstractTableModel, который можно настроить для указания (и отображения) другой базы данных при необходимости:

class DatabaseModel : public QAbstractTableModel
{
    Q_OBJECT

public:
    DatabaseModel(QObject *parent = 0);

    int rowCount(const QModelIndex &parent = QModelIndex()) const { return _data->itemCount(); }
    int columnCount(const QModelIndex &parent = QModelIndex()) const { return 5; };

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const = 0;

    void setDatabase(const Database *data);
    {
        beginResetModel();
        _data = data;
        endResetModel();
    }

protected:
    const Database *_data;
};

У меня проблема с тем, чтобы модель отразила изменения в ее текущей базе данных. Раньше я заставлял его работать, выполняя сброс модели каждый раз, когда что-то менялось в базе данных (вызванное сигналом из базы данных в DatabaseModel), но решил, что это излишне. Теперь я понятия не имею, как правильно связать базу данных и модель.

Подключение сигналов базы данных к модели и заставить модель излучать dataChanged () не работает, потому что количество элементов в базе данных (и, следовательно, строк в модели) меняется. В QAbstractTableModel есть сигналы, которые называются rowInserted () и rowRemoved (), но в документах говорится, что их нельзя использовать в пользовательских классах. Существуют виртуальные функции, которые должны быть переопределены, которые называются removeRows () и insertRows (), но в документах говорится, что я должен вызывать begin (Remove | Insert) Rows () и end (Remove | Insert) Rows () внутри них, что приводит к двум проблемам

  1. begin ... Rows () нужен параметр «parent» QModelIndex, для которого я понятия не имею, что использовать
    РЕДАКТИРОВАТЬ: На самом деле это не имеет значения, теперь я передаю QModelIndex () для этого. Это используется QAbstractTreeModel для идентификации родительского узла в дереве и, по-видимому, не требуется для табличных моделей.
  2. в документах говорится, что эти функции необходимо вызвать до изменения базового хранилища данных

Как заставить модель синхронизироваться с базой данных? Спасибо!

1 Ответ

7 голосов
/ 03 мая 2011

Мне кажется, я вижу твою проблему.С одной стороны, вы делаете правильные вещи и пытаетесь отделить данные от модели, с другой стороны, ваши данные не знают о самой модели.

Есть причина, по которой вам следуетвызовите begin ... Rows () перед изменением данных и end ... Rows () впоследствии.А именно QPersistentModelIndex.Обычно вы не должны набирать QModelIndex объекты, но постоянный индекс должен быть сохранен и сохранен.Модель должна гарантировать ее действительность.Глядя на код этих методов begin ... Rows (), речь идет в основном об этих постоянных индексах.

У вас есть несколько вариантов выбора.
a) Если вы уверены, что не будете использоватьпостоянные индексы, вы можете просто внедрить частный слот в вашей модели, который прослушивает своего рода сигнал обновления из вашего источника данных.Этот слот будет просто вызывать begin ... Rows () и end ... Rows (), между которыми ничего нет.Это не «чисто», но это будет работать.

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

c) Вы можете сделать свой класс DataBase другом в модели и вызвать методы begin ... end ... из своего источника данных,но тогда DataBase должен был бы знать о модели.

d) Вы могли бы переосмыслить концепцию.Из того, что я могу понять, вы используете класс DataBase в качестве хранилища данных для вашей модели и в качестве интерфейса для других частей вашего кода, верно?Не проще ли использовать пользовательские элементы с методами, которые работают с самой моделью и, таким образом, позволяют избежать проблем?Я сделал все возможное, чтобы в случае необходимости дать вам код.

Надеюсь, это поможет.
С уважением

...