Подтвердить что ты не робот

Доступ к QLists С++ из QML

Если у меня есть список вещей на С++, как я могу представить это в QML (в Qt5/QtQuick 2)? Похоже, что QML может понимать только классы QObject -derived, что является проблемой, потому что QObject нельзя поместить в QList или скопировать. Как это сделать:

struct Thing
{
    int size;
    QString name;
};

class ThingManager : public QObject
{
    Q_OBJECT

    // These macros support QtQuick, in case we one day want to use it to make a slick
    // interface (when QML desktop components are released).
    Q_PROPERTY(QList<Thing> things READ things NOTIFY thingssChanged)

public:
    // ...
    QList<Thing> things() const;

    // ...

};

Итак, я могу сделать что-то подобное в QML:?

var a = thingManager.things[0].name;
4b9b3361

Ответ 1

После большего опыта работы с QML я нашел лучший способ иметь списки вещей с QAbstractListModel.

Вы делаете свой Thing из QObject, поэтому его можно сохранить в QVariant (после его регистрации). Затем вы можете вернуть фактический Thing в качестве элемента модели. Вы можете получить доступ к нему в Repeater как model.display.a_property_of_thing. Длина списка доступна как model.count.

Это имеет следующие плюсы и минусы:

  • Fast - он не копирует весь список для доступа к одному элементу.
  • Вы можете легко получить анимацию для внесения изменений в список (добавление, перегруппировка и удаление элементов).
  • Он прост в использовании из QML.
  • Чтобы активировать анимацию, всякий раз, когда вы меняете список, вам нужно немного облегчить бухгалтерию (beginInsertRows() и т.д.).

...

class Things : public QObject
{
...
};

Q_DECLARE_METATYPE(Thing*)

class ThingList : public QAbstractListModel
{
    Q_OBJECT

public:
    explicit ThingList(QObject *parent = 0);
    ~ThingList();

    int rowCount(const QModelIndex& parent = QModelIndex()) const override;
    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;

public slots:

    // Extra function to get the thing easily from outside Repeaters.
    Thing* thing(int idx);

private:
    QList<Thing*> mThings;
};

int ThingList::rowCount(const QModelIndex& parent) const
{
    return mThings.size();
}

QVariant ThingList::data(const QModelIndex& index, int role) const
{
    int i = index.row();
    if (i < 0 || i >= mPorts.size())
        return QVariant(QVariant::Invalid);

    return QVariant::fromValue(mThings[i]);
}

Thing* ThingList::thing(int idx)
{
    if (idx < 0 || idx >= mThings.size())
        return nullptr;

    return mThings[idx];
}

Ответ 2

Я столкнулся с этим вопросом, пытаясь исправить аналогичную проблему, где я хотел использовать код С++ в качестве источника модели в QML. Ответ, данный TheBootroo, указал мне в правильном направлении, но не работал полностью для меня. У меня недостаточно репутации, чтобы отвечать на него напрямую (но я ответил на его ответ).

Я использую Qt 5.0.0 Я нашел эту ссылку очень полезно

Определение ThingManager должно быть изменено следующим образом

class ThingManager : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<QObject*> things READ getThings NOTIFY thingsChanged)

public:
    QList<QObject*> getThings () const { return m_things; }

signals:
    void thingsChanged ();

private:
    QList<QObject*> m_things;
};

Обратите внимание, что я изменил возвращаемый тип getThings на QList < QObject * > . Без этого изменения Qt предупреждает, что это "Невозможно обрабатывать незарегистрированный тип данных" QList < Thing * > ".

В QML-коде свойства Thing можно получить через модель как model.modelData.size и model.modelData.name.

Ответ 3

В качестве альтернативы вы можете использовать QVariantList (QList<QVariant>), он автоматически изменится на массив JavaScript при передаче в QML и будет доступен для чтения и записи из С++ и QML

Ответ 4

А я нашел ответ (я думаю, не тестировался): QQmlListProperty

В примерах несколько примеров, например. при qtdeclarative/examples/quick/tutorials/gettingStartedQml/filedialog/directory.*:

К сожалению, на данный момент вы можете иметь только списки только для чтения.

Ответ 5

вы совершенно ошибаетесь в QObject, их можно присвоить QList, просто в форме указателя, так как следующее работает отлично:

class Thing : public QObject
{
    Q_OBJECT

    Q_PROPERTY (int     size READ getSize CONSTANT)
    Q_PROPERTY (QString name READ getName CONSTANT)

public:
    Thing(QObject * parent = NULL) : QObject(parent) {}

    int     getSize () const { return m_size; }
    QString getName () const { return m_name; }

private:
    int     m_size;
    QString m_name;
};

class ThingManager : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<Thing*> things READ getThings NOTIFY thingsChanged)

public:
    QList<Thing*> getThings () const { return m_things; }

signals:
    void thingsChanged ();

private:
    QList<Things*> m_things;
};

Ответ 6

Ответ, заданный eatyourgreens, правильный. Внедряя свой класс таким образом, вы можете получить доступ к как можно большему количеству потомков. Еще один полезный совет, который я нашел полезным, - создать псевдоним для нашей модели внутри элемента делегата qml.

ListView {
   anchors.fill: parent
   model: thing_manager.things
   delegate: ItemDelagate {}
   clip: true
   spacing: 10
}

И затем в ItemDelegate.qml вы можете создать псевдоним для модели, чтобы не использовать все время model.modelData​​p >

Item{
    width: 600
    height: 200
    property var thing: model.modelData
    Rectangle {
        anchors.fill: parent
        color: "red"
        Text {
            text: thing.name // or any other field
        }
    }
}

Ответ 7

Одним из весьма косвенных способов достижения этого является следующее:

i.) Сделайте модель в qml

ListModel 
{
     id: thingModel

     ListElement 
     {
         size: 10
         name: "Apple"
     }     
}

ii.) Затем предоставьте пару функций javascript, чтобы изменить этот список, например.

function jAppendThing( newSize, newName )
{
    thingModel.append({"size": nameSize, "name": newName })
}

function jClearThing()
{
    thingModel.clear()
}

аналогично jDeleteThing и т.д.

iii.) Вы можете прочитать как вызвать qml-функции из С++

iv.) Запустите цикл в списке С++ и вызовите функцию добавления qml, чтобы добавить все эти данные в список qml.

v.) В любом обновлении в боковом списке С++ также измените данные qml, используя указанную выше функцию, чтобы обновить ее.

Ответ 9

Используйте хорошее, но не упомянутое решение:

class ThingManager : public QObject
{
Q_OBJECT

// These macros support QtQuick, in case we one day want to use it to make a slick
// interface (when QML desktop components are released).
Q_PROPERTY(QList<Thing> things MEMBER m_things NOTIFY thingssChanged)

// ...
private:
// ...
QList<Thing> m_things;
// ...

};

Чтение и запись применимы. Нет дорогостоящего вызова функции и копирования данных. Просто прямой доступ к членам класса в QML:

var a = thingManager.things[0].name;

Для получения дополнительной информации см. документ: https://doc-snapshots.qt.io/qt5-dev/properties.html