Dostęp do C++ QLists z QML

Jeśli mam listę rzeczy w C++, jak to zrobić w QML (w Qt5 / QtQuick 2)? Wygląda na to, że QML może zrozumieć tylko klasy pochodne QObject, co jest problemem, ponieważ QObject s nie można umieścić w QList lub skopiować. Jak to zrobić:

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;

    // ...

};

Żebym mógł zrobić coś takiego w QML:?

var a = thingManager.things[0].name;
Author: Timmmm, 2013-01-12

9 answers

Natknąłem się na to pytanie, próbując rozwiązać podobny problem, w którym chciałem użyć kodu C++ jako źródła modelu w QML. Odpowiedź udzielona przez TheBootroo wskazała mi właściwy kierunek, ale nie zadziałała w pełni dla mnie. Nie mam wystarczającej reputacji, aby odpowiedzieć mu bezpośrednio (ale głosowałem na jego odpowiedź).

Używam Qt 5.0.0 Znalazłem ten link bardzo pomocny

Definicja ThingManager powinna zostać zmieniona w następujący sposób

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;
};

Zauważ, że zmieniłem zwraca typ getThings do listy QList. Bez tej zmiany Qt ostrzega, że "nie jest w stanie obsłużyć niezarejestrowanego typu danych' QList'".

W kodzie QML, właściwości rzeczy mogą być dostępne poprzez model jako model.modelData.rozmiar i model.modelData.name.

 21
Author: eatyourgreens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-05 11:34:36

Alternatywnie, można użyć QVariantList (QList<QVariant>), po przekazaniu do QML automatycznie zmieni się na tablicę JavaScript i będzie można ją odczytywać i zapisywać z C++ i QML

 20
Author: Dickson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-14 16:20:44

Po więcej doświadczeń z QML znalazłem najlepszy sposób, aby mieć listy rzeczy jest z QAbstractListModel.

Tworzysz Thing z QObject, więc może być przechowywany w QVariant (Po zarejestrowaniu). Następnie możesz zwrócić rzeczywistą Thing jako element modelu. Możesz uzyskać do niego dostęp w Repeater jako model.display.a_property_of_thing. Długość listy jest dostępna jako model.count.

Ma to następujące zalety i wady:

  1. szybko - nie kopiuje całej listy, aby uzyskać dostęp do jednej element.
  2. możesz łatwo uzyskać animacje zmian na liście(dodawanie, przestawianie i usuwanie elementów).
  3. jest łatwy w użyciu z QML.
  4. aby animacje działały, za każdym razem, gdy zmieniasz listę, musisz wykonać nieco faffy bookkeeping (beginInsertRows() itp.)

...

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];
}
 8
Author: Timmmm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-07 10:55:01

[[2]] Ah znalazłem odpowiedź (chyba nie sprawdzoną): QQmlListProperty

Jest kilka zastosowań w przykładach, np. w qtdeclarative/examples/quick/tutorials/gettingStartedQml/filedialog/directory.*:

Niestety w tej chwili możesz mieć tylko listy tylko do odczytu.

 4
Author: Timmmm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-11 23:39:09

Mylisz się co do QObject, mogą one być podane do QList, po prostu w formie wskaźnika, ponieważ następujące działania działają doskonale:

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;
};
 2
Author: TheBootroo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-29 08:48:44

Odpowiedź udzielona przez eatyourgreens jest prawidłowa. Implementując w ten sposób swoją klasę, możesz uzyskać dostęp do tylu Potomków, ilu chcesz. Jeszcze jedna pomocna wskazówka, którą uznałem za przydatną, to utworzenie aliasu dla naszego modelu wewnątrz elementu delegata qml.

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

A następnie w ItemDelegate.qml możesz utworzyć alias dla modelu, aby nie używać go przez cały czas.modelData

Item{
    width: 600
    height: 200
    property var thing: model.modelData
    Rectangle {
        anchors.fill: parent
        color: "red"
        Text {
            text: thing.name // or any other field
        }
    }
}
 1
Author: Mr.Coffee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-10 12:29:46

Best way use QQmlListProperty .zobacz tę prostą próbkę, mam nadzieję, że ci pomogę.
obiekt i lista typów właściwości przykład

 1
Author: Programer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-21 13:38:15

Jednym z bardzo pośrednich sposobów osiągnięcia tego jest:

I.) zrób model w qml

ListModel 
{
     id: thingModel

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

Ii.) następnie podaj kilka funkcji javascript, aby zmodyfikować tę listę np.

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

function jClearThing()
{
    thingModel.clear()
}

Podobnie jDeleteThing itp..

Iii.) możesz przeczytać o Jak wywoływać funkcje qml z c++

Iv.) Uruchom pętlę na liście C++ i wywołaj funkcję dołączania qml, aby dodać wszystkie te dane do listy qml.

V.) przy każdej aktualizacji w C++, zmodyfikuj qml dane, jak również za pomocą powyższej funkcji, aby je aktualizować.

 0
Author: Amit Tomar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-11 23:14:34

Istnieje dobre, ale nie wymienione rozwiązanie:

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;
// ...

};

Odczyt i zapis mają zastosowanie. Brak kosztownego wywołania funkcji i kopiowania danych. Po prostu bezpośredni dostęp do członków klasy w QML:

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

Aby uzyskać więcej informacji, zobacz doc: https://doc-snapshots.qt.io/qt5-dev/properties.html

 0
Author: fokhagyma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-23 10:52:02