QAbstractListModel and QList adapter

My application stores several objects of a type that inherits from QAbstractListModel objects.

This generates quite a lot of duplicate code when packing a simple std::vector<T> or QList<T> into a model with general addition, deletion and multi-screen selection.

Is it supposed that the QAbstractListModel path should be used, or is there some adapter class that can remove duplicate code (at least for containers that are part of Qt)?

Example. I want to wrap vector<ObjectA> and vector<ObjectB> in a model. Code for insertRows , deleteRows , columnCount , etc. It will always be the same, and I would like to combine it (with a little metaprogramming, which can work even with tuple and data ).

+4
source share
2 answers

You have to do this in two separate classes, because Qt extensions for C ++ (SIGNALS, SLOTS, etc.) do not go well with templates. Justification and workaround for this can be found at: http://doc.qt.digia.com/qq/qq15-academic.html

Here is a rough solution diagram. (This is based on the code we use in our application, and it works fine.)

1. An abstract list class that makes Qt material

 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. An abstract class that makes pattern materials

 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. Actual list class

 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. ... }; 
+6
source

Normally, I myself would implement my own model, inheriting from QAbstractItemModel , and provide my own implementation for presentation functions such as data() to handle the data storage container that I give the model.

If you have code duplication to use QList<T> and std::vector<T> , I would suggest converting one to another by doing:

 QList<T> list = QList::fromVector(QVector::fromStdVector(vector)); 

or another way.

 std::vector<T> vector = qlist.toVector().toStdVector(); 

I would do the latter, but you can also choose.

Based on your additional comments, you can choose two paths:

Path 1:

Add objectA and objectB as follows:

 class objectA : baseObject 

and

 class objectB : baseObject 

where baseObject :

 struct baseObject { virtual std::string toString() = 0; }; 

It is probably easier to convert to a string, and then something else.

Path 2 will basically include inside the model, using std::vector<boost::any>() as a container for storing data, so you can implement a subclass of one model QAbstractListModel .

What you should consider is that if your data storage container you can possibly distribute the data view, you are limited by what you can do, because the data() function that will give your view, the element must return a QVariant and it is limited by what you can build it from.

+1
source

Source: https://habr.com/ru/post/1391452/


All Articles