Qt:用点表示法从QML访问C ++对象

时间:2016-12-26 20:02:16

标签: c++ qt qml qt5

我想通过点符号使用方括号从QML访问我的应用程序的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

我应该使用什么机制以 HIERARCHICAL 点表示法形式公开我的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对象。

1 个答案:

答案 0 :(得分:1)

您不能使用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,您可以使用[]运算符,但仅限于索引访问。而且您无法直接从对象执行此操作,您必须从对象的列表属性中执行此操作,例如object.listProperty[index]。我注意到,即使您在代码中包含QQmlListProperty,它也没有真正实现。

因此,如果您将任务实现为QQmlListProperty User,那么您可以执行以下操作:

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

请确保您不会超出界限。你还有tasks.length来避免这种情况。

我并不确切知道这是如何实现的,但QQmlListProperty本身及相关类型并未实现[]运算符。我的猜测是这是在QML引擎级别实现的,可能不是公共API的一部分或直接可用,这对于Qt内部来说非常典型。