QAbstractListModel и адаптер QList - PullRequest
       29

QAbstractListModel и адаптер QList

4 голосов
/ 17 января 2012

Мое приложение хранит несколько объектов типа, который наследуется от QAbstractListModel объектов.

Это генерирует довольно много дублирующегося кода при объединении простого std::vector<T> или QList<T> в модель собщие функции добавления, удаления и множественного выбора.

Это способ, которым предполагается использовать QAbstractListModel, или есть какой-то класс адаптера, который может удалить дублирующийся код (по крайней мере, для контейнеров, являющихся частью Qt)?

Пример: я хочу обернуть vector<ObjectA> и vector<ObjectB> в модель.Код для insertRows, deleteRows, columnCount и т. Д. Всегда будет одним и тем же, и я хотел бы объединить его (с небольшим количеством метапрограммирования, которое может работать даже с tuple и data).

Ответы [ 2 ]

6 голосов
/ 17 января 2012

Вы должны сделать это в двух отдельных классах, потому что расширения Qt для c ++ (SIGNALS, SLOTS и т. Д.) Плохо работают с шаблонами. Обоснование и обходной путь для этого можно найти по адресу: 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. ...
};
1 голос
/ 17 января 2012

Обычно я реализую свою собственную модель, унаследованную от 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, и она ограничена тем, из чего вы можете построить его.

...