QAbstractListModel и адаптер QList
-
29-10-2019 - |
Вопрос
Мое приложение хранит несколько объектов типа, который наследуется от
QAbstractListModel
объекты.
Это генерирует довольно много дублированного кода при переносе простого
std::vector<T>
или в QList<T>
в модель с общей функциональностью добавления,
удаления и множественного выбора.
Это тот самый способ QAbstractListModel
предполагается использовать или есть
какой-то класс адаптера, который может удалить дублированный код (по крайней мере, для
контейнеров, которые являются частью Qt)?
Пример:Я хочу завернуть vector<ObjectA>
и vector<ObjectB>
в модель.Код для insertRows
, deleteRows
, columnCount
и т.д.всегда будет одним и тем же, и я хотел бы закрепить это (с помощью небольшого метапрограммирования, которое могло бы работать даже с tuple
и data
).
Решение
Вы должны сделать это в двух отдельных классах, потому что расширения Qt для c++ (СИГНАЛЫ, слоты и т.д.) плохо сочетаются с шаблонами.Обоснование и обходной путь для этого можно найти по адресу: http://doc.qt.digia.com/qq/qq15-academic.html
Вот приблизительный набросок решения.(Это основано на коде, который мы используем в нашем приложении, и который работает нормально.)
1.Абстрактный класс списка, который выполняет функции 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.Абстрактный класс, который выполняет шаблонные функции
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.Фактический класс списка
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. ...
};
Другие советы
Обычно я бы реализовал свою собственную модель, наследующую от QAbstractItemModel
непосредственно и предоставляю свою собственную реализацию для функций презентации, таких как data()
для обработки контейнера для хранения данных я даю модель.
Если у вас есть дублирование кода для использования QList<T>
и std::vector<T>
тогда я бы предложил преобразовать одно в другое, выполнив либо:
QList<T> list = QList::fromVector(QVector::fromStdVector(vector));
или в другую сторону.
std::vector<T> vector = qlist.toVector().toStdVector();
Я бы сделал последнее, но вы можете выбрать и то, и другое.
Основываясь на ваших дополнительных комментариях, вы можете предпринять 2 варианта действий:
Путь 1:
Осуществлять objectA
и objectB
следующим образом:
class objectA : baseObject
и
class objectB : baseObject
где baseObject
является:
struct baseObject
{
virtual std::string toString() = 0;
};
Вероятно, проще преобразовать в строку, чем что-либо еще.
Путь 2 в основном будет включать в себя использование внутри модели std::vector<boost::any>()
в качестве контейнера для хранения данных, таким образом, вы можете реализовать единый подкласс модели QAbstractListModel
.
Дело в том, что вы должны учитывать, что если ваш контейнер для хранения данных вы, вероятно, можете сделать общим для представления данных, вы ограничены в том, что вы можете сделать, потому что data()
функция, которая передаст вашему представлению, что элемент должен возвращать QVariant
и он ограничен тем, из чего вы можете его сконструировать.