Pregunta

En mi aplicación, tengo una clase para mantener una lista de elementos:

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

Las funciones de manipulación del elemento (agregar, actualizar, eliminar) emiten las señales correspondientes cuando se realizan (elementos agregados, cambiados, eliminados). Tengo una lista de dichas bases de datos y una vista QtableView para mostrar su contenido. También tengo un objeto de una clase de modelo personalizada y derivada de qAbstracttableModel, que se puede hacer señalar (y mostrar) una base de datos diferente cuando sea necesario:

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

Tengo un problema con hacer que el modelo refleje los cambios en su base de datos actual. Antes, hice que funcionara emitiendo un reinicio del modelo cada vez que algo cambiaba en la base de datos (activada por una señal de la base de datos al DataBASEModel), pero decidió que era exagerado. Ahora no tengo idea de cómo conectar la base de datos y el modelo correctamente.

Conectar las señales de la base de datos al modelo y hacer que el modelo emita datachanged () no funciona porque el número de elementos en la base de datos (y por lo tanto las filas del modelo) está cambiando. Hay señales llamadas showsinserted () y showsremoved () en qabstracttableModel, pero los documentos dicen que no se pueden usar en clases personalizadas. Hay funciones virtuales que se reimplementarán llamadas removerows () e inserTrows (), pero los documentos dicen que debo llamar a comenzar (eliminar | insertar) filas () y finalizar (eliminar | insertar) filas () dentro de ellos, lo que lleva a dos problemas a dos problemas :

  1. Begin ... filas () necesita un parámetro Qmodelindex 'padre', para el cual no tengo idea de qué usar
    EDITAR: En realidad, no importa, ahora estoy pasando QModelIndex () para esto. QaBstractTreeModel lo utiliza para identificar un nodo principal en un árbol y aparentemente no es necesario para los modelos de tabla.
  2. Los documentos dicen que estas funciones deben llamarse antes de Cambiar el almacén de datos subyacente

¿Cómo hago que el modelo se mantenga sincronizado con la base de datos? ¡Gracias!

¿Fue útil?

Solución

Creo que veo tu problema. Uno de un lado que está haciendo lo correcto e intentando mantener los datos separados del modelo, por otro lado, sus datos no son conscientes del modelo en sí.

Hay una razón por la que debe llamar a Begin ... filas () antes de cambiar los datos y finalizar ... filas () después. A saber el QPersistentModelIndex. Por lo general, se supone que no debes hort QModelIndex Objetos, pero el índice persistente es para ser guardado y guardado. El modelo debe garantizar su validez. Mirando el código de esos métodos Begin ... filas () Se trata principalmente de esos índices persistentes.

Tienes varias opciones.
a) Si está positílicamente seguro que no utilizará índices persistentes, simplemente podría implementar una ranura privada en su modelo que escucha una especie de señal de actualización de su fuente de datos. Esta ranura simplemente llamaría a ... filas () y terminar ... filas () sin nada en el medio. No está "limpio", pero funcionará.

b) Puede implementar más señales en su fuente de datos, una que indique el comienzo de un cambio de datos (eliminación o adición de una fila, por ejemplo) y otra que indique el final de dicha operación. Por supuesto, eso aumentaría significativamente el tamaño de su código.

c) Podrías hacer tu DataBase Clase un amigo en el modelo y llame al comienzo ... fin ... métodos desde su fuente de datos, pero luego DataBase Tendría que ser consciente del modelo.

D) Podrías repensar el concepto. Por lo que puedo entender, estás usando el DataBase Clase como almacenamiento de datos para su modelo y como interfaz para otras partes de su código, ¿verdad? ¿No sería más fácil usar elementos personalizados con métodos que funcionan en el modelo en sí y, por lo tanto, evitar el problema? He hecho mi parte justa de ellos para poder darte el código si es necesario.

Ojalá eso ayude.
Saludos

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top