簡體   English   中英

Qt:通過點表示法從QML訪問C ++對象

[英]Qt: Accessing C++ objects from QML by dot notation

我想使用方括號通過點表示法從QML訪問我的App的C ++類,例如:

myapp.object1.child_object2["key1"].grandchild_object1.property56
myapp.object2.child_object8[291045].grandchild_object4.property14

我希望能夠將這些(C ++)對象綁定到QML屬性或在Javascript代碼中使用它們。 什么是快速而適當的方法?

例如,假設MyApp有一個Users對象,它是QAbstractItemModel類,並且具有用戶QMap()。 此QMap中的每個條目都有一個電子郵件地址作為鍵,以及一個User()對象,其中包含用戶屬性,例如電子郵件,姓名等。因此,在這種情況下,點符號為:

myapp.users["johnsmith@domain.com"].name
myapp.users["johnsmith@domain.com"].password

稍后,我將使其變得更加復雜,例如為JohnSmith的任務添加帶有QMap()對象的第二層層次結構:

myapp.users["johnsmith@domain.com"].tasks[1].task_name
myapp.users["johnsmith@domain.com"].tasks[2].task_name

我應該使用什么機制以分層的點表示形式公開C ++對象? 我了解PROPERTY宏在Qt中的工作原理,但是如何使其能夠用於分層點符號呢? 我應該在QAbstractItemModel類的子類中使用其他方法還是應該重載[]運算符? 是否有可能(完全)使QML引擎中的[]運算符過載? 最后一個問題是,如果此時無法在Qt中使用分層點符號,那么通過修改源代碼是否會很難實現?

到目前為止,這是我的源代碼:

// File: main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "myapp.h"
#include "users.h"
#include "user.h"
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    qmlRegisterType<MyApp>("com.myapp",1,0,"MyApp");
    qmlRegisterType<Users>("com.myapp.users",1,0,"Users");
    qmlRegisterType<User>("com.myapp.user",1,0,"User");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));

    return app.exec();
}

MyApp類 標頭:

//File: myapp.h


#ifndef MYAPP_H
#define MYAPP_H

#include <QObject>
#include <QQmlListProperty>
#include "users.h"

class MyApp : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Users *users READ get_users WRITE set_users NOTIFY usersChanged);
private:
    Users               m_users;
public:
    explicit MyApp(QObject *parent = 0);
    Q_INVOKABLE Users *get_users();
    void set_users(Users *data);
signals:
    void usersChanged();
};
#endif // MYAPP_H

C源碼:

//File: myapp.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "myapp.h"
#include "users.h"
#include "user.h"
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    qmlRegisterType<MyApp>("com.myapp",1,0,"MyApp");
    qmlRegisterType<Users>("com.myapp.users",1,0,"Users");
    qmlRegisterType<User>("com.myapp.user",1,0,"User");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));

    return app.exec();
}

用戶文件 標頭:

//File: users.h

#ifndef USERS_H
#define USERS_H

#include <QObject>
#include <QAbstractItemModel>
#include <QMap>
#include "user.h"

class Users : public QAbstractItemModel
{
    Q_OBJECT
    enum UserRoles {
        EmailRole = Qt::UserRole + 1,
        NameRole,
        PasswordRole
    };
private:
    QMap<QString,User*>         users_map;
public:
    explicit Users(QAbstractItemModel *parent = 0);
    Q_INVOKABLE QModelIndex index(int row, int column,const QModelIndex &parent = QModelIndex()) const;
    Q_INVOKABLE QModelIndex parent(const QModelIndex &child) const;
    Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const;
    Q_INVOKABLE int columnCount(const QModelIndex &parent = QModelIndex()) const;
    Q_INVOKABLE QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    QHash<int, QByteArray> roleNames() const;
signals:

public slots:
};    
#endif // USERS_H

資源:

//File: users.cpp
#include <QDebug>
#include "users.h"

Users::Users(QAbstractItemModel *parent) : QAbstractItemModel(parent)
{
    User *u;
    u=new User();
    u->set_email("johnsmith@domain.com");
    u->set_name("John Smith");
    u->set_password("123");
    users_map.insert(u->get_email(),u);
    u=new User();
    u->set_email("juliepage@domain.com");
    u->set_name("Julie Page");
    u->set_password("321");
    users_map.insert(u->get_email(),u);
}
QModelIndex Users::parent(const QModelIndex &child) const {
    return QModelIndex();
}
QModelIndex Users::index(int row, int column,const QModelIndex &parent) const {

    QList <QString> qlist;
    qlist=users_map.keys();
    if (row>=qlist.size()) return QModelIndex();
    User *user=users_map[qlist.at(row)];
    return createIndex(row,column,user);
}
int Users::rowCount(const QModelIndex &parent) const {
    return users_map.size();
}
int Users::columnCount(const QModelIndex &parent) const {
    return 1;
}
QVariant Users::data(const QModelIndex &index, int role) const {
    int row_num;

    row_num=index.row();
    if (role==EmailRole) {
        QList <QString> qlist;
        qlist=users_map.keys();
        if (row_num>=qlist.size()) return (QVariant());
        return QVariant(qlist.at(row_num));
    }
    if (role==NameRole) {
        QList <QString> qlist;
        qlist=users_map.keys();
        if (row_num>=qlist.size()) return (QVariant());
        User *user=users_map.value(qlist.at(row_num));
        return QVariant(user->get_name());
     }
    if (role==PasswordRole) {
        QList <QString> qlist;
        qlist=users_map.keys();
        if (row_num>=qlist.size()) return (QVariant());
        User *user=users_map[qlist.at(row_num)];
        return QVariant(user->get_password());
    }
    if (role==Qt::DisplayRole) {
        return(QVariant());
    }
    return (QVariant());
}
QHash<int, QByteArray> Users::roleNames() const {
    QHash<int, QByteArray> roles;
    roles[EmailRole] = "email";
    roles[NameRole] = "name";
    roles[PasswordRole] = "password";
    return roles;
}

用戶文件 標頭:

//File user.h
#ifndef USER_H
#define USER_H

#include <QObject>

class User : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString email READ get_email WRITE set_email NOTIFY emailChanged);
    Q_PROPERTY(QString name READ get_name WRITE set_name NOTIFY nameChanged);
    Q_PROPERTY(QString password READ get_password WRITE set_password NOTIFY passwordChanged);
private:
    QString             email;
    QString             name;
    QString             password;
public:
    explicit User(QObject *parent = 0);
    const QString get_email();
    void set_email(QString data);
    const QString get_name();
    void set_name(QString data);
    const QString get_password();
    void set_password(QString data);
signals:
    void emailChanged();
    void nameChanged();
    void passwordChanged();
};
#endif // USER_H

資源:

//File: user.cpp

#include "user.h"

User::User(QObject *parent) : QObject(parent)
{

}
const QString User::get_email() {
    return email;
}
void User::set_email(QString data) {
    if (email!=data) {
        email=data;
        emit emailChanged();
    }
}
const QString User::get_name() {
    return name;
}
void User::set_name(QString data) {
    if (name!=data) {
        name=data;
        emit nameChanged();
    }
}
const QString User::get_password() {
    return password;
}
void User::set_password(QString data) {
    if (password!=data) {
        password=data;
        emit passwordChanged();
    }
}

QML文件。

//File: main.qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0

import com.myapp 1.0;
import com.myapp.users 1.0;
import com.myapp.user 1.0;

ApplicationWindow {
    visible: true; width:640; height: 480;
    MyApp {
        id:myapp
    }
    ListView {
        model: myapp.users
        width: 300; height: 300
        delegate: ItemDelegate {
            Text {
                text: model.email
            }
        }
    }
    Component.onCompleted: {
        var users=myapp.users;
        var user=users["johnsmith@domain.com"];
        console.log("users object=" + users);
        console.log("user object=" + user);
        console.log("user's name="+user.name);
    }
}

項目文件。 //文件:QML1.pro

QT += qml quick

CONFIG += c++11

SOURCES += main.cpp \
    myapp.cpp \
    users.cpp \
    user.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Default rules for deployment.
include(deployment.pri)

HEADERS += \
    myapp.h \
    users.h \
    user.h

和調試輸出,當我運行程序時:

qml: users object=Users(0x15cd1b0)
qml: user object=undefined
qrc:/main.qml:28: TypeError: Cannot read property 'name' of undefined

如您所見,我不能超越[]方括號,因為QML不會檢索User對象。

您不能從QML對C ++對象使用運算符,如果要從QML訪問,則需要使用函數。 如果您已經具有帶有運算符的對象,則可以編寫調用該運算符的函數包裝。

只要QML知道對象,就可以使用點語法,即順序詞,它需要為對象生成元信息。 因此,對象必須是QObject派生的,或使用Q_GADGET並公開為Q_INVOKABLE函數或Q_PROPERTY

在這種情況下,請使用:

myapp.object1.child_object2["key1"].grandchild_object1.property56

你會

//    prop    prop          invokable   prop               prop
myapp.object1.child_object2.get("key1").grandchild_object1.property56

或者如果您通過訪問器函數實現子對象:

myapp.object1().child_object2().get("key1").grandchild_object1().property56

更新:

請注意,對於正確實現的QQmlListProperty ,可以使用[]運算符,但只能用於索引訪問。 而且,您不能直接從對象執行此操作,而必須從對象的list屬性(例如object.listProperty[index] 我注意到,即使您在代碼中包含QQmlListProperty ,也並未真正實現它。

因此,如果將任務作為UserQQmlListProperty ,則可以執行以下操作:

myapp.users.get("johnsmith@domain.com").tasks[1].task_name

只要確保您不超出范圍即可。 您也可以使用tasks.length來避免這種情況。

我不知道該如何實現,但是QQmlListProperty本身和關聯的類型沒有實現[]運算符。 我的猜測是,這是在QML引擎級別上實現的,並且可能不是公共API的一部分,也不是直接可使用的,這對於Qt內部來說是很典型的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM