Search code examples
qtqmlqt5

Is it possible to create binding proxy in qt qml?


i have a cpp struct which have so much fields

struct CloudMusicSongList{ ... };

and i want use it in qml in order input some infomation to it's instance, but i don't want to create a qobject derived class,and create a lot of qproperty ... i seache in google and get this code snippt from this blog

class ListItem : public QObject
{
 Q_OBJECT
public :
 ListItem(QObject *parent = 0) : QObject(parent) {}
 virtual ~ListItem() {}
 virtual int id() const = 0;
 virtual QVariant data(int role) const = 0;
 virtual QHash<int, QByteArray> roleNames() const = 0;
 virtual void triggerItemUpdate() {emit dataChanged();}
signals:
 void dataChanged();
};

i just try following code but even not print called data method

defined.h


template <typename T>
class bindingProxy : public bindingProxyBase
{
  public:
    bindingProxy(QObject* parent = 0)
        : bindingProxyBase(parent)
    {
    }
    T tm;
    virtual ~bindingProxy()
    {
    }
    virtual QVariant data(int role)
    {
        qDebug() << "called data method";
        QVariant qv;
        auto fucs = Prism::Reflection::get_md<T>();
        if (role == Qt::DisplayRole)
            fucs[0].getFunc(tm, 0, qv);
        else
            fucs[role].getFunc(tm, role, qv);
        return qv;
    }
    QHash<int, QByteArray> roleNames() const
    {
        static QHash<int, QByteArray> roles{};
        if (roles.count() == 0)
        {
            for (Prism::Reflection::PrismMetaData<T>& item : Prism::Reflection::get_md<T>())
            {
                roles[item.offset] = item.name;
            }
        }
        return roles;
    }
    bool setData(QVariant& value, int role = Qt::EditRole)
    {
        Prism::Reflection::get_md<T>()[role].setFunc(tm, role, value);
        triggerItemUpdate();
        return true;
    }
};

bodyViewModel.cpp

#include ....
...
..

Q_DECLARE_METATYPE(bindingProxy<CloudMusicSongList>*);
class BodyViewModel : public QObject
{

    Q_PROPERTY(bindingProxy<CloudMusicSongList>* editSongListModel READ editSongListModel WRITE setEditSongListModel NOTIFY editSongListModelChanged)

...
...
...


uing.qml

 Button {
     id:btn_tst
     text: BodyViewModelCpp.editSongListModel.name + "hbb"
     onClicked: BodyViewModelCpp.editSongListModel.name = "3232"
 }


button look like this image after run app rung

enter image description here

i don't know whether it is the X Y problem.
somebody can help? thanks

i want create a bindingProxy template class which twoway bindable in qml i think it should equivalence dynamicObject in wpf


Solution

  • Based on CloudMusicSongList I'm assuming the thing that you have is a list/array. There are quite a number of ways of exposing this to QML.

    QQmlListProperty is a list of QObjects. It requires the underlying QObject be registered, but, allows you to create/manage and walk through a list of the results. The list is owned, usually by another QObject. e.g. we could have a QmlFile object, then implement a QmlFileSystem object that can return a list of QmlFiles.

    QAbstactListModel can be used in places where a model is required, e.g. ListView.

    QVariant, QVariantList and QVariantMap is the simplest way of creating a Javascript object in QML. The advantage is you do not have to register anything, but, the disadvantage is you do not get intellisense.

    QVariant getBooks() {
        QVariantList books;
        QVariantMap book1;
        book1["title"] = QString("Lord of the Rings");
        QVariantMap book2;
        book2["title"] = QString("The Hobbit");
        books.append(book2);
        return books;
        // results in QML/JS:
        // [ { "title": "Lord of the Rings" },
        //   { "title" : "The Hobbit" } ]
    }