我想通过点符号使用方括号从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
对象。
答案 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内部来说非常典型。