Adaptateur QabStractListmodel et QList
-
29-10-2019 - |
Question
Mon application stocke quelques objets d'un type qui hérite deQAbstractListModel
objets.
Cela génère beaucoup de code dupliqué lors de l'emballage d'un simplestd::vector<T>
ou un QList<T>
dans le modèle avec les fonctionnalités générales d'ajout, de suppression et multi-sélection.
Est-ce le chemin QAbstractListModel
est censé être utilisé ou y a-t-il une classe d'adaptateur qui peut supprimer le code dupliqué (au moins pour les conteneurs qui font partie de QT)?
Exemple: je veux envelopper vector<ObjectA>
et vector<ObjectB>
dans un modèle. Le code pour insertRows
, deleteRows
, columnCount
etc. va toujours être le même et je voudrais consolider cela (avec une petite méta-programmation qui pourrait même fonctionner avec tuple
et data
).
La solution
Vous devez le faire dans deux classes distinctes car les extensions de QT vers C ++ (signaux, machines à sous, etc.) ne jouent pas bien avec les modèles. La justification et la solution de contournement pour cela peuvent être trouvées à: http://doc.qt.digia.com/qq/qq15-academic.html
Voici un aperçu approximatif d'une solution. (Ceci est basé sur le code que nous utilisons dans notre application et cela fonctionne bien.)
1. Classe de liste abstraite qui fait des trucs QT
class FooListModelQt : public QAbstractTableModel {
Q_OBJECT
public:
// Non-template methods, signals, slots, etc. can be used here. For example...
QSet<int> SelectedRows() const;
// ... etc. ...
signals:
void SelectionChanged();
// ... etc. ...
protected:
explicit FooListModelQt(QObject *parent = NULL);
virtual ~FooListModelQt() = 0;
// ... etc. ...
};
2. classe abstraite qui fait des trucs de modèle
template <typename T>
class FooListModel : public FooListModelQt {
public:
const T* at(int index) const { return items_.at(index); }
int count() const { return items_.count(); }
void Append(T *item);
// ... etc. ...
protected:
explicit FooListModel(QObject *parent = NULL);
virtual ~FooListModel();
private:
QList<T*> items_;
};
3. Classe de liste réelle
class BarListModel : public FooListModel<Bar> {
Q_OBJECT
public:
explicit BarListModel(QObject *parent = NULL);
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
// ... etc. ...
};
Autres conseils
Normalement, j'implémenterais mon propre modèle héritant de QAbstractItemModel
directement et fournir ma propre implémentation pour les fonctions de présentation telles que data()
Pour gérer le conteneur de stockage de données, je donne le modèle.
Si vous avez du code de duplication pour l'utilisation QList<T>
et std::vector<T>
Ensuite, je suggérerais de convertir l'un à l'autre en faisant soit:
QList<T> list = QList::fromVector(QVector::fromStdVector(vector));
ou dans l'autre sens.
std::vector<T> vector = qlist.toVector().toStdVector();
Je ferais ce dernier mais vous pouvez choisir non plus.
Sur la base de vos commentaires supplémentaires, vous pouvez emprunter 2 chemins d'action:
Chemin 1:
Mettre en place objectA
et objectB
comme suit:
class objectA : baseObject
et
class objectB : baseObject
où baseObject
est:
struct baseObject
{
virtual std::string toString() = 0;
};
Probablement plus facile à convertir en chaîne que toute autre chose.
Le chemin 2 impliquera essentiellement à l'intérieur du modèle en utilisant std::vector<boost::any>()
Comme votre conteneur de stockage de données, vous pouvez implémenter un seul modèle de sous-classe QAbstractListModel
.
La chose que vous devez considérer que si votre conteneur de stockage de données, vous pouvez probablement faire de la présentation des données, vous êtes limité à ce que vous pouvez faire parce que data()
Fonction qui donnera votre avis que l'élément doit revenir QVariant
Et c'est limité à ce à quoi vous pouvez le construire.