[英]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
,也並未真正實現它。
因此,如果將任務作為User
的QQmlListProperty
,則可以執行以下操作:
myapp.users.get("johnsmith@domain.com").tasks[1].task_name
只要確保您不超出范圍即可。 您也可以使用tasks.length
來避免這種情況。
我不知道該如何實現,但是QQmlListProperty
本身和關聯的類型沒有實現[]
運算符。 我的猜測是,這是在QML引擎級別上實現的,並且可能不是公共API的一部分,也不是直接可使用的,這對於Qt內部來說是很典型的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.