Как QMap передать в qml и вывести в ComboBox?

185
11 января 2020, 07:20

Не понимаю как QMap <int, ThreeDModelTexture*> mapTexture; передать в qml . Класс ThreeDModelTexture у меня такой :

threedmodeltexture.h

#ifndef THREEDMODELTEXTURE_H
#define THREEDMODELTEXTURE_H
#include <QString>
#include <QObject>
#include <QString>
#include <QAbstractListModel>
#include <QList>
#include <QVariant>
#include <QModelIndex>
#include "baseqmlabstractlistmodel.h"
class Texture;
class ThreeDModelTexture: public QAbstractListModel
{
public:
    ThreeDModelTexture(QObject *parent = nullptr);
    enum ThreeDModelRolse {
        nameRole = Qt::DisplayRole,
        idModelRole = Qt::UserRole + 1,
        urlRole = Qt::UserRole + 2
    };
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    int rowCount(const QModelIndex &parent) const; // количество элементов в модели
    void addTexture(Texture ct);
    Q_INVOKABLE Texture setContent();
public slots:
    QHash<int, QByteArray> roleNames() const;
private:
    QList<Texture> textures;
    QHash<int, QByteArray> roles; // роли
};
class Texture
{
public:
    Texture(int _idModel, QString _name, QString _url)
    {
        idModel = _idModel;
        name = _name;
        url = _url;
    }
    void setName (QString _name)
    {
        name = _name;
    }
    void seturl (QString _url)
    {
        url = _url;
    }
    void setidModel (int _idModel)
    {
        idModel = _idModel;
    }
    QString getName() const
    {
        return name;
    }
    QString getUrl() const
    {
        return url;
    }
    int getIDModel() const
    {
        return idModel;
    }
private:
    int idModel;
    QString name;
    QString url;
};
#endif // THREEDMODELTEXTURE_H

threedmodeltexture.cpp

#include "threedmodeltexture.h"
ThreeDModelTexture::ThreeDModelTexture(QObject *parent) :
    QAbstractListModel(parent)
{
    roles[idModelRole] = "idModel";
    roles[nameRole] = "name";
    roles[urlRole] = "url";
}
QVariant ThreeDModelTexture::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() > textures.count())
        return QVariant();
    const Texture & ct = textures[index.row()];
        if (role == idModelRole)
            return ct.getIDModel();
        else if (role == nameRole)
            return ct.getName();
        else if (role == urlRole)
            return ct.getUrl();
        return QVariant();
}
QHash<int, QByteArray> ThreeDModelTexture::roleNames() const
{
    return roles;
}
Texture ThreeDModelTexture::setContent()
{
    return textures.last();
}
void ThreeDModelTexture::addTexture(Texture ct)
{
    textures << ct;
}
int ThreeDModelTexture::rowCount(const QModelIndex &parent) const
{
    return textures.size();
}

Я в main.cpp его добавляю в QMap :

...
ThreeDModelTexture *TextureModel= new ThreeDModelTexture();
QMap<int, ThreeDModelTexture*> mapTexture;
                TextureModel->addTexture(Texture(1,
                                                "aaa",
                                                "aaa.jpg"));
                TextureModel->addTexture(Texture(1,
                                                "bbb",
                                                "bbb.jpg"));
 mapTexture.insert(1,TextureModel);
                TextureModel->addTexture(Texture(2,
                                                "ttt",
                                                "ttt.jpg"));
                TextureModel->addTexture(Texture(2,
                                                "mmm",
                                                "mmm.jpg"));
 mapTexture.insert(2,TextureModel);
...

Как теперь в qml вы вести его в combobox-сах , чтоб idModel тут они 1 и 2 соответствовал список

Answer 1

Рекомендую немного изменить подход к взаимодействию qml и с++.

Вам требуется заполнить необходимой информацией combobox в qml. Для этого вам нужен список моделей объектов с соответствующими идетификаторами, а также список наименований текстур и их идентификаторы. Создадим соответствующие легковесные структуры.

Пусть класс модели называется ObjectParameters:

struct ObjectParameters {
    Q_GADGET // <- это взамен наследования QObject
    int id; // уникальный идентификатор модели объекта
    QString name; // Имя модели
}

Класс текстуры берем ваш:

struct Texture {
    Q_GADGET
    int id;
    QString name;
    QString url;
}

Эти струтуры можно использовать в качестве полей ваших классов логики на С++.

Допустим у вас есть класс Object, который выполняет всю работу по созданию модели объекта, ее загрузки, выгрузки, чтения файлов, обработки комманд пользователя и так далее. И в качестве его поля мы можем сделать объект стуктуры ObjectParameters:

class Object
{
//...
    const ObjectParameters& params() const;
// Здесь идут сложные методы работы с моделью
private:
    ObjectParameters _params;
// Еще какие-то поля, но которые не нужны в qml
}

Далее где-то и как-то инициализировали и загрузили ваши модели. Теперь нам надо отобразить о них информацию на пользовательском интерфейсе.

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

Теперь создадим класс-посредник взаимодействия c++ и qml. Назовем его Logic. Он будет принимать от qml запросы, обращаться к объектам С++, формировать ответ и возвращать его.

class Logic : public QObject
{
    Q_OBJECT
public:
    int objectCount() const;
    const ObjectParameters& object(int index) const;
    int textureCount() const;
    const Texture& textures(int index) const;
public slots:
    // Присвоение модели  выбранной текстуры
    void appendTexture(int objectId, int textureId) 
    {
        // Находим объект по его objectId
        // и добавляем к нему новую текстуру по textureId
    }
private:
    QList<Object> _objects;
    QList<Texture> _textures;
}

Не забываем зарегистрировать Logic в qml и постараться все взаимодействие между qml и с++ выполнять через данный класс посредник-обертку надо бэкендом.

Qml. Допустим наш интерфейс состоит из перечня имен моделей-объектов (с идентификаторами), а также комбобокса для каждой модели, который содержит список имен текстур (и их идентификаторы).

ApplicationWindow
{
    ListView
    {
        model: listViewModel
        delegate: Row
        {
            Text { text: "Name: " + _text }
            property int id: _id
            ComboxBox { 
                model: ListModel {
                    id: comboModel
                }
                // Этот метод вызывается один раз
                // при создании компонента
                Component.onCompleted: {
                    // Заполняем model комбобокса
                    for(var i = 0; i < logic.textureCount(); i++)
                    {
                        var tex = logic.texture(i);
                        comboModel.append({"text" : tex.name, "id": tex.id});
                    }
                }
                onActivated: {
                    // Событие выбора нового элемента в комбо
                    // тут нам доступен аргумент index
                    // Присваиваем моделе с идентификатором _id
                    // новую текстуру
                    logic.appendTexture(_id, comboModel.get(index).id)
                }
            }
        }
    }
    ListModel
    {
        id: listViewModel
    }
    // Загружаем список объектов при создании объекта ApplicationWindow
    Component.onCompleted: {
        // Подгружаем объекты
        for( var i = 0; i < logic.objectCount(); i++ )
        {
            var obj = logic.objectParameters(i);
            listViewModel.append({"_text": obj.name, "_id": obj.id});                       
        }
    }
    Logic {
        id: logic
    }
}
READ ALSO
Использование стороннего компилятора clang на macOS для Qt qmake

Использование стороннего компилятора clang на macOS для Qt qmake

Мне надо собрать проект C++ QtУ меня установлен llvm-8, в pro-файле указанно

146
Как вставить массив в массив на языке С++?

Как вставить массив в массив на языке С++?

У меня есть 2 массива вида:

142
Двойное условие на сигнал в connect

Двойное условие на сигнал в connect

Можно ли сделать двойное условие на сигнал (например, при нажатии на кнопку в одном случае срабатывала одна функция, а при другом - другая)...

149