Как выставить список пользовательских объектов с помощью Q_PROPERTY - PullRequest
0 голосов
/ 16 октября 2018

У меня очень простой класс с 2 свойствами;ключ и значение:

KeyValue.h:

class KeyValue : public QObject
{
  Q_OBJECT
  Q_PROPERTY(QString key READ getKey WRITE setKey NOTIFY keyChanged)
  Q_PROPERTY(QString value READ getValue WRITE setValue NOTIFY valueChanged)

 public:
  KeyValue(const QString& key, const QString& value, QObject* parent = 0);  

 signals:
  void keyChanged();
  void valueChanged();

 private:
  QString _key;
  QString _value;

  QString getKey() const;
  QString getValue() const;

  void setKey(const QString& key);  
  void setValue(const QString& value);
};
Q_DECLARE_METATYPE(KeyValue)

В другом классе я хотел бы свойство, содержащее список объектов KeyValue, поэтому я могу использовать этот списоккак модель в QML.

Controller.h

class Controller : public QObject
{
  Q_OBJECT
  Q_PROPERTY(QList<KeyValue*> items READ getItems NOTIFY itemsChanged)

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

 signals:
  void itemsChanged(); 

 private:
  QList<KeyValue*> getItems() const;
};

Я хочу использовать это в QML следующим образом:

import QtQuick 2.7
import customqml 1.0

Item{
  Controller{
    id: controller
  }
  Repeater{
    model: controller.items
    Text{
      text: modelData.key + ": " + modelData.value
    }
  }
}

Оба класса зарегистрированы в моем файле main.cpp:

qmlRegisterType<KeyValue>("customqml", 1, 0, "KeyValue");
qmlRegisterType<Controller>("customqml", 1, 0, "Controller");

Приведенный выше код не работает, потому что, очевидно, я не могу напрямую открыть QList для QML.Я пытался использовать QAbstractItemModel и QQmlListProperty, но мне не удалось заставить его работать.Кто-нибудь может указать мне правильное направление?

Мои основные проблемы - это тип свойства items в классе Controller и возвращаемое значение метода getItems .

Я использую Qt 5.9, если это что-то меняет.

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Примечание:

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

  • Классы, которые наследуютиз QObject не требуется QMetaType, потому что, когда вы хотите передать данные этого класса, используются указатели.

Не все типы данных поддерживаются QML через Q_PROPERTY, поэтому возможное решение состоит в том, чтобыэкспорт через известные классы, такие как

  • QList<QObject *>:

class Controller : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<QObject *> items READ getItems NOTIFY itemsChanged)
public:
    explicit Controller(QObject *parent = nullptr);
    QList<QObject *> getItems() const;
signals:
    void itemsChanged();
private:
    QList<KeyValue *>key_values_list;
};

...
QList<QObject *> Controller::getItems() const
{
    QObjectList l;
    for(auto e: key_values_list)
        l << e;
    return l;
}
  • QVariantList:

class Controller : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QVariantList items READ getItems NOTIFY itemsChanged)
public:
    explicit Controller(QObject *parent = nullptr);
    QVariantList getItems() const;
signals:
    void itemsChanged();
private:
    QList<KeyValue *>key_values_list;
};

...
QVariantList Controller::getItems() const
{
    QVariantList l;
    for(auto e: key_values_list)
        l.append(QVariant::fromValue(e));
    return l;
}

Другие варианты - реализация модели, в следующем примере показана только модель только для чтения:

keyvaluemodel.h

#ifndef KEYVALUEMODEL_H
#define KEYVALUEMODEL_H

#include "keyvalue.h"

#include <QAbstractListModel>

class KeyValueModel : public QAbstractListModel
{
    Q_OBJECT

public:
    explicit KeyValueModel(QObject *parent = nullptr)
        : QAbstractListModel(parent)
    {
        key_values_list = {new KeyValue{"k", "v"}, new KeyValue{"k2", "v2"}};
    }
    int rowCount(const QModelIndex &parent = QModelIndex()) const override
    {
        if (parent.isValid())
            return 0;
        return key_values_list.length();
    }
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
    {
        if (!index.isValid())
            return QVariant();
        if(index.row() >= 0 && index.row() < rowCount())
            return QVariant::fromValue(key_values_list[index.row()]);
        return QVariant();
    }
private:
    QList<KeyValue* >key_values_list;
};

#endif // KEYVALUEMODEL_H

class Controller : public QObject
{
    Q_OBJECT
    Q_PROPERTY(KeyValueModel* items READ getItems NOTIFY itemsChanged)
public:
    explicit Controller(QObject *parent = nullptr);
    KeyValueModel* getItems() const;
signals:
    void itemsChanged();
private:
    KeyValueModel *model;
};

...
Text{
    text: display.key + ": " + display.value
}
...

И аналогичным образом вы можете реализовать QQmlListProperty, в документации естьмного примеров.

0 голосов
/ 16 октября 2018

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

В качестве простого, но менее гибкого способа вы можете использовать QVariantList и сделайте ваш класс контроллера типом значения.Вам необходимо:

  • Макрос Q_DECLARE_METATYPE (Controller) в конце заголовочного файла Controller.
  • Конструктор копирования для Controller
  • Конструктор по умолчанию для Controller

Q_PROPERTY Тип и возвращаемое значение тогда QVariantList.

...