将 QML 对象加载到 C++ 应用程序中时,直接嵌入一些可在 QML 代码中使用的 C++ 数据会很有用。 例如,这使得在嵌入对象上调用 C++ 方法或使用 C++ 对象实例作为 QML 视图的数据模型成为可能。
QQmlContext 类使将 C++ 数据注入 QML 对象的能力成为可能。此类向 QML 对象的上下文公开数据,以便可以直接从 QML 代码范围内引用数据。
一、设置简单的上下文属性
例如,这里有一个 QML 项,它引用了当前作用域中不存在的 currentDateTime 值:
// MyItem.qml
import QtQuick 2.0
Text
{
text: currentDateTime
}
这个值可以由加载 QML 组件的 C++ 应用程序使用 QQmlContext::setContextProperty() 直接设置:
QQuickView view;
view.rootContext()->setContextProperty("currentDateTime",QDateTime::currentDateTime());
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
view.show();
由于在 QML 中计算的所有表达式都是在特定上下文中计算的,如果修改了上下文,则将重新计算该上下文中的所有绑定。因此,应在应用程序初始化之外谨慎使用上下文属性,因为这可能会导致应用程序性能下降。
二、将对象设置为上下文属性
上下文属性可以包含 QVariant 或 QObject* 值。 这意味着也可以使用这种方法注入自定义 C++ 对象,并且可以直接在 QML 中修改和读取这些对象。修改上面的例子,嵌入一个 QObject 实例而不是一个 QDateTime 值,QML 代码在对象实例上调用一个方法:
class ApplicationData : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE QDateTime getCurrentDateTime() const
{
return QDateTime::currentDateTime();
}
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
ApplicationData data;
QQuickView view;
view.rootContext()->setContextProperty("applicationData", &data);
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
view.show();
return app.exec();
}
// MyItem.qml
import QtQuick 2.0
Text
{
text: applicationData.getCurrentDateTime()
}
(请注意,从 C++ 返回到 QML 的日期/时间值可以通过 Qt.formatDateTime() 和相关函数进行格式化。)
如果 QML 项需要从上下文属性接收信号,它可以使用 Connections 类型连接到它们。 例如,如果 ApplicationData 有一个名为 dataChanged() 的信号,则可以使用 Connections 对象中的 onDataChanged 处理程序连接到该信号:
Text
{
text: applicationData.getCurrentDateTime()
Connections
{
target: applicationData
onDataChanged: console.log("The application data changed!")
}
}
三、上下文属性与C++ 的数据模型示例
3.1、字符串列表模型
int main(int argc, char ** argv)
{
QGuiApplication app(argc, argv);
QStringList dataList;
dataList.append("Item 1");
dataList.append("Item 2");
dataList.append("Item 3");
dataList.append("Item 4");
QQuickView view;
QQmlContext *ctxt = view.rootContext();
ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
view.setSource(QUrl("qrc:view.qml"));
view.show();
return app.exec();
}
import QtQuick 2.0
ListView
{
width: 100; height: 100
model: myModel
delegate: Rectangle
{
height: 25
width: 100
Text { text: modelData }
}
}
3.2、对象列表模型
#ifndef DATAOBJECT_H
#define DATAOBJECT_H
#include <QObject>
class DataObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
public:
DataObject(QObject *parent=nullptr);
DataObject(const QString &name, const QString &color, QObject *parent=nullptr);
QString name() const;
void setName(const QString &name);
QString color() const;
void setColor(const QString &color);
signals:
void nameChanged();
void colorChanged();
private:
QString m_name;
QString m_color;
};
#endif // DATAOBJECT_H
#include <QDebug>
#include "dataobject.h"
DataObject::DataObject(QObject *parent)
: QObject(parent)
{
}
DataObject::DataObject(const QString &name, const QString &color, QObject *parent)
: QObject(parent), m_name(name), m_color(color)
{
}
QString DataObject::name() const
{
return m_name;
}
void DataObject::setName(const QString &name)
{
if (name != m_name)
{
m_name = name;
emit nameChanged();
}
}
QString DataObject::color() const
{
return m_color;
}
void DataObject::setColor(const QString &color)
{
if (color != m_color)
{
m_color = color;
emit colorChanged();
}
}
#include "dataobject.h"
int main(int argc, char ** argv)
{
QGuiApplication app(argc, argv);
QList<QObject*> dataList;
dataList.append(new DataObject("Item 1", "red"));
dataList.append(new DataObject("Item 2", "green"));
dataList.append(new DataObject("Item 3", "blue"));
dataList.append(new DataObject("Item 4", "yellow"));
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
QQmlContext *ctxt = view.rootContext();
ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
view.setSource(QUrl("qrc:view.qml"));
view.show();
return app.exec();
}
import QtQuick 2.0
ListView
{
width: 100; height: 100
model: myModel
delegate: Rectangle
{
height: 25
width: 100
color: model.modelData.color
Text { text: name }
}
}
3.3、QAbstractItemModel
#include <QAbstractListModel>
#include <QStringList>
class Animal
{
public:
Animal(const QString &type, const QString &size);
QString type() const;
QString size() const;
private:
QString m_type;
QString m_size;
};
class AnimalModel : public QAbstractListModel
{
Q_OBJECT
public:
enum AnimalRoles
{
TypeRole = Qt::UserRole + 1,
SizeRole
};
AnimalModel(QObject *parent = nullptr);
void addAnimal(const Animal &animal);
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
protected:
QHash<int, QByteArray> roleNames() const;
private:
QList<Animal> m_animals;
};
#include "model.h"
Animal::Animal(const QString &type, const QString &size)
: m_type(type), m_size(size)
{
}
QString Animal::type() const
{
return m_type;
}
QString Animal::size() const
{
return m_size;
}
AnimalModel::AnimalModel(QObject *parent)
: QAbstractListModel(parent)
{
}
void AnimalModel::addAnimal(const Animal &animal)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_animals << animal;
endInsertRows();
}
int AnimalModel::rowCount(const QModelIndex & parent) const
{
Q_UNUSED(parent)
return m_animals.count();
}
QVariant AnimalModel::data(const QModelIndex & index, int role) const
{
if (index.row() < 0 || index.row() >= m_animals.count())
return QVariant();
const Animal &animal = m_animals[index.row()];
if (role == TypeRole)
return animal.type();
else if (role == SizeRole)
return animal.size();
return QVariant();
}
QHash<int, QByteArray> AnimalModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[TypeRole] = "type";
roles[SizeRole] = "size";
return roles;
}
int main(int argc, char ** argv)
{
QGuiApplication app(argc, argv);
AnimalModel model;
model.addAnimal(Animal("Wolf", "Medium"));
model.addAnimal(Animal("Polar bear", "Large"));
model.addAnimal(Animal("Quoll", "Small"));
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
QQmlContext *ctxt = view.rootContext();
ctxt->setContextProperty("myModel", &model);
view.setSource(QUrl("qrc:view.qml"));
view.show();
return app.exec();
}
import QtQuick 2.0
ListView
{
width: 200; height: 250
model: myModel
delegate: Text { text: "Animal: " + type + ", " + size }
}