2017-01-11 20 views
1

У меня есть класс модели, наследующий QAbstractListModel:Qt Доступ к модели данных за пределами ItemDelegate

VehiclesModel.h:

class VehiclesModel : public QAbstractListModel { 
    Q_OBJECT 

    public: 
     enum Roles { 
      ImagePathRole = Qt::UserRole + 1, // QString 
      NameRole       // QString 
     }; 

     virtual int rowCount(const QModelIndex & parent = QModelIndex()) const override { ... } 
     virtual QVariant data(const QModelIndex & index, int role) const override { ... } 
     virtual QHash<int, QByteArray> roleNames() const override { 
      QHash<int, QByteArray> roles = QAbstractListModel::roleNames(); 

      roles[ImagePathRole] = "imagePath"; 
      roles[NameRole] = "name"; 

      return roles; 
     } 
}; 

main.cpp:

#include "VehiclesModel.h" 

int main(int argc, char * argv[]) { 
    QGuiApplication app(argc, argv); 
    VehiclesModel vehiclesModel; 
    QQmlApplicationEngine engine; 

    engine.rootContext()->setContextProperty("vehiclesModel", &vehiclesModel); 
    engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 
    return app.exec(); 
} 

И ComboBox, который отображает эту модель: main.qml:

ComboBox { 
    id: control 
    model: vehiclesModel 
    delegate: ItemDelegate { 
     contentItem: RowLayout { 
      Image { 
       source: imagePath 
      } 
      Label { 
       text: name 
      } 
     } 
     highlighted: control.highlightedIndex == index 
    } 
    contentItem: RowLayout { 
     Image { 
      source: ??imagePath?? 
     } 
     Label { 
      text: ??name?? 
     } 
    } 
} 

Я хочу настроить ComboBox, чтобы показать изображение и название автомобиля. Я могу получить доступ к данным модели от ItemDelegate, но как получить доступ к данным модели за пределами ItemDelegate? Например, я хочу получить данные текущего индекса (ImagePathRole и NameRole), чтобы отобразить изображение и имя транспортного средства в contentItem.

Можно ли сделать это без вызова QAbstractListModel методов напрямую (т.е. index() и data() методы) и делает их Q_INVOKABLE?

ответ

2

В настоящее время, к сожалению, в каком-то приличном встроенном способе, к сожалению, этого не хватало, и я подумал о том, чтобы реализовать что-то для этого в моделях QML функциональности, но у меня еще не было времени на это.

В настоящее время вы можете сделать это самостоятельно (как вы обсуждаете), ценой безопасности типа и т. Д. (Или, как я обычно это рассматривал раньше), вы можете создать подкласс QObject для представления одного элемента в модели (ItemDataThing или того, что вы хотите назвать); предоставить ему исходную модель & индекс, свойства, и пусть он представляет собой один экземпляр данных из модели.

Что-то вроде:

class ImageDataThing : public QObject 
{ 
    Q_OBJECT 
    Q_PROPERTY(QString imagePath READ imagePath NOTIFY imagePathChanged) 
    Q_PROPERTY(QAbstractItemModel* model READ model WRITE setModel NOTIFY modelChanged) 
    Q_PROPERTY(int index READ index WRITE setIndex NOTIFY indexChanged) 

public: 
    QString imagePath() const; 
    QAbstractItemModel *model() const; 
    void setModel(const QAbstractItemModel *newModel); 
    int index() const; 
    void setIndex(int newIndex); 
signals: 
    void imagePathChanged(const QString &imagePath); 
    void modelChanged(QAbstractItemModel *model); 
    void indexChanged(int indexChanged); 
}; 

... и в своей реализации, когда модель устанавливается, зацепить изменения сигналов (например, rowsInserted, rowsRemoved, ...), чтобы изменить сохраненный индекс (если это предусмотрено), чтобы он отображался в нужное место в модели.

В образцах данных модели (здесь, например, imagePath) обращайтесь к экземпляру модели (используя индекс), чтобы извлечь данные и вернуть их.

У этого есть очевидный недостаток, заключающийся в том, что он является большим количеством шаблонов, но, с другой стороны, это простой в использовании код, если вы знакомы с моделями, безопасными по типу, и можно легко автогенерировать его довольно легко.

1

Вы можете создать свою собственную функцию, чтобы получить данные из модели, как тот, который я сейчас использую, VehiclesModel.h:

public slots: 
    int size() const; // to access from QML javascript 
    QVariant getData(int index, int role); // to access from QML javascript 

VehiclesModel.cpp:

int VehiclesModel::size() const { 
    return m_list.size(); 
} 

QVariant VehiclesModel::getData(int index, int role) { 
    if (index < 0 || index >= m_list.count()) 
     return QVariant(); 
    switch (role) { 
    case ImagePathRole: 
     return ... 
     break; 
    default: 
     break; 
    } 
} 
1

я настоятельно рекомендую посмотреть на Qt QML Tricks библиотека, сделанная Томасом Бутроу:

http://gitlab.unique-conception.org/qt-qml-tricks/

конкретизируют QQmlObjectListModel (от Qt QML Models) может сделать трюк для вас.

Расширение с использованием Qt Super-Macros, оно уменьшает накладные устройства для стрижки/геттеры! Эти макросы в основном расширяются до Q_PROPERTY, что приводит к доступности из QML и добавляет определение сеттера, получателя и частной переменной.

Использование в вашем конкретном случае это может выглядеть примерно так, быстро записал, не подтверждено (проверьте с помощью правильный индекс для ссылки на модели):

VehicleItem.h:

#include <QObject> 
#include "QQmlVarPropertyHelpers.h" // Include library Qt Super-Macros 

class VehicleItem : public QObject { 
    Q_OBJECT 

    QML_WRITABLE_VAR_PROPERTY(QString, imagePath) 
    QML_WRITABLE_VAR_PROPERTY(QString, name) 

public: 
    explicit VehicleItem(QString imagePath, QString name, QObject* parent=0) 
    : QObject (parent) 
    , m_imagePath (imagePath) 
    , m_name  (name) 
    {} 

}; 

VehiclesModel.h:

#include <QObject> 
#include "QQmlObjectListModel.h" // Include library Qt QML Models 
#include "VehicleItem.h" 

class VehiclesModel : public QObject { 
    Q_OBJECT 

    QML_OBJMODEL_PROPERTY(VehicleItem, modelList) 

public: 
    explicit VehiclesModel(QObject *parent = 0); 

}; 

VehiclesModel.c:

#include "VehiclesModel.h" 

VehiclesModel::VehiclesModel(QObject *parent) : 
    QObject(parent), m_modelList(new QQmlObjectListModel<VehicleItem>()) 
{} 

main.c (remains the same):

#include "VehiclesModel.h" 

int main(int argc, char * argv[]) { 
    QGuiApplication app(argc, argv); 
    VehiclesModel vehiclesModel; 
    QQmlApplicationEngine engine; 

    engine.rootContext()->setContextProperty("vehiclesModel", &vehiclesModel); 
    engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 
    return app.exec(); 
} 

main.qml:

ComboBox { 
    id: control 
    model: vehiclesModel 
    delegate: ItemDelegate { 
     contentItem: RowLayout { 
      Image { 
       source: imagePath 
      } 
      Label { 
       text: name 
      } 
     } 
     highlighted: control.highlightedIndex == index 
    } 
    contentItem: RowLayout { 
     Image { 
      source: vehiclesModel.modelList.get(index).imagePath 
     } 
     Label { 
      text: vehiclesModel.modelList.get(index).name 
     } 
    } 
} 

В modelList (а также ImagePath и название) расширяется за счет макро- к Q_PROPERTY, она доступна с QML стороны.

Для входов и выходов из этой библиотеки, не забудьте проверить молниеносный разговор Томаса Бутро в в QtWS2015: https://www.youtube.com/watch?v=96XAaH97XYo

+0

Как это «точно, что ищет OP»? Не могли бы вы объяснить это в своем ответе?Что вы подразумеваете под «простым и приятным синтаксисом с минимальными накладными расходами, записывающими ваши сеттеры/геттеры»? Как это относится к вопросу? Я также не вижу смысла вашего последнего предложения (Q_PROPERTY используются для определения ролей модели, а не для доступа к модели в QML). – GrecKo

+0

См. Обновленный ответ. – Bartel

+0

Спасибо за обновление вашего ответа и показ того, как можно использовать lib. Мои вопросы по-прежнему остаются без ответа, ожидаются 2 первых. Простым и приятным синтаксисом, я считаю, вы говорите о его qt-supermacros lib, который неясно, что вы используете в своем ответе. Ваше предложение о Q_PROPERTY все еще не ясно и довольно расплывчато. – GrecKo

0

Shameless плагин для моего SortFilterProxyModel library.

Проблема, о которой вы просите, на самом деле является сценарием с головой. Я нашел способ сделать это несколько правильно, но это довольно сложно и связано с внешней библиотекой. В моем решении мы фильтруем исходную модель, чтобы выставлять только элемент, соответствующий текущему индексу поля со списком, и создавать экземпляр делегата для этого элемента и использовать его как contentItem из ComboBox.

Это имеет то преимущество, что вам не нужно модифицировать вашу модель и поддерживать синхронизацию с вашими изменениями модели.

import SortFilterProxyModel 0.2 // from https://github.com/oKcerG/SortFilterProxyModel 
import QtQml 2.2 

/* 
... 
*/ 

ComboBox { 
    id: control 
    model: vehiclesModel 
    delegate: ItemDelegate { 
     contentItem: RowLayout { 
      Image { 
       source: imagePath 
      } 
      Label { 
       text: name 
      } 
     } 
     highlighted: control.highlightedIndex == index 
    } 
    contentItem: { currentIndex; return selectedInstantiator.object; } // use currentIndex to force the binding reevaluation. When the model changes, the instantiator doesn't notify object has changed 
    Instantiator { 
     id: selectedInstantiator 
     model: SortFilterProxyModel { 
      sourceModel: control.model 
      filters: IndexFilter { 
       minimumIndex: control.currentIndex 
       maximumIndex: control.currentIndex 
      } 
     } 
     delegate: RowLayout { 
      Image { 
       source: imagePath 
      } 
      Label { 
       text: name 
      } 
     } 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^