×
Namespaces

Variants
Actions

在C++程序中使用QML

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata

兼容于
平台:
Symbian

文章
Cxt_programmer 在 20 Dec 2010 创建
最后由 hamishwillee 在 11 Oct 2012 编辑

本文翻译自Using QML in C++ Applications。欢迎大家编辑、修改此文章。

QML API有三个主要成员——QDeclarativeEngineQDeclarativeComponentQDeclarativeContext

QDeclarativeEngine提供了QML的运行环境。 QDeclarativeComponent封装了QML DocumentsQDeclarativeContext允许程序使用QML组件显示数据。

QML包含一个非常好用的API——QDeclarativeView。通过它,应用程序可以很方便的把QML组件嵌入到QGraphicsView中。QDeclarativeView主要用于在应用程序开发过程中进行快速原型开发,它的主要特性将在下面讨论。

如果你正打算用QML改造现有的Qt应用程序,请参考QML与Qt UI代码整合

Contents

基本用法

若想将QML与C++程序结合,程序中至少需要一个QDeclarativeEngine。只有程序中需要使用多个不同的QML组件实例时,才需要多个QDeclarativeEngine。为了使所有QML组件实例可以工作,QDeclarativeEngine为他们提供全局配置,QDeclarativeEngine对于C++中使用QML的作用如同QNetworkAccessManager对于网络通信、路径对于持久化存储的作用。

可以使用QDeclarativeComponent加载QML Documents。每一个QDeclarativeComponent实例对应一个QML document。

可以传递一个Document URL或者表示Document内容的原始文本给QDeclarativeComponent。Document URL可以是本地文件系统URL,或者任何QNetworkAccessManager支持的网络URL。

可以通过QDeclarativeComponent::create()方法创建QML组件实例。下面的代码演示了如何加载一个QML Document并创建一个实例:

QDeclarativeEngine *engine = new QDeclarativeEngine(parent);
QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml"));
QObject *myObject = component.create();

暴露数据(Exposing Data)

QML组件在QDeclarativeContext中实例化。一个上下文(context)允许程序暴露数据给QML组件实例。一个QDeclarativeContext可用于创建应用程序中用到的所有对象实例,如果需要精确控制为每个实例暴露的数据,可以创建多个QDeclarativeContex。如果上下文(context)没有传递给QDeclarativeComponent::create()方法,将默认使用QDeclarativeEngine的根上下文(root context),这时数据通过跟上下文(root context)暴露给所有对象实例。

简单数据(Simple Data)

向QML组件实例暴露数据,通过QML属性绑定(Property Bindings)和JavaScript对象访问应用程序设置上下文属性(context properties)。下面的例子展示了如何通过QDeclarativeView暴露背景颜色给QML文件:

// main.cpp
#include <QApplication>
#include <QDeclarativeView>
#include <QDeclarativeContext>
 
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
 
QDeclarativeView view;
QDeclarativeContext *context = view.rootContext();
context->setContextProperty("backgroundColor",
QColor(Qt::yellow));
 
view.setSource(QUrl::fromLocalFile("main.qml"));
view.show();
 
return app.exec();
}
// main.qml
 
import QtQuick 1.0
 
Rectangle {
width: 300
height: 300
 
color: backgroundColor
 
Text {
anchors.centerIn: parent
text: "Hello Yellow World!"
}
}

如果你只希望在main.cpp里创建组件,不想显示在QDeclarativeView中,需要使用QDeclarativeEngine::rootContext()来创建QDeclarativeContext实例:

     QDeclarativeEngine engine;
QDeclarativeContext *windowContext = new QDeclarativeContext(engine.rootContext());
windowContext->setContextProperty("backgroundColor", QColor(Qt::yellow));
 
QDeclarativeComponent component(&engine, "main.qml");
QObject *window = component.create(windowContext);

上下文属性(Context Properties)的工作方式同QML绑定(QML bindings)中的普通属性(normal properties)一样,在上面的例子中,当上下文属性(context poperty)backgroundColor变为红色时,组件对象实例都会自动更新。请注意创建者有责任删除它创建的QDeclarativeContext。当销毁Window组件时,windowContext必须被显式的销毁(手动delete),或者用一种更简单的方法——设置windowContext的父类为window(父对象释放时,会自动释放所有子对象)。

QDeclarativeContexts以树状结构组织,除了根上下文(root context)外,每个QDeclarativeContext都有一个父对象。QDeclarativeContexts子对象有效的继承父对象的上下文属性(context properties),这使得应用程序更加灵活的在不同的QML对象实例间暴露(exposed)数据。如果QDeclarativeContext设置了一个与父对象相同的上下文属性(context property),父对象的这个属性将被“隐藏”。如下面的例子所示,Context1中的上下文属性(context property)background“隐藏”了根上下文(root context)中的background属性。


Qml context tree.png


结构化数据(Structed Data)

上下文属性(context property)还可用于向QML对象暴露结构化可写数据。除了QVariant已经支持的所有类型外,派生自QObject的类型也可分配给上下文属性(context property)。QObject上下文属性(context property)允许暴露结构化的数据,并允许QML对这些数据设值。 下面的例子创建了一个CustomPalette对象,并将它设为名为palette的上下文属性(context property):

 class CustomPalette : public QObject
{
Q_OBJECT
Q_PROPERTY(QColor background READ background WRITE setBackground NOTIFY backgroundChanged)
Q_PROPERTY(QColor text READ text WRITE setText NOTIFY textChanged)
 
public:
CustomPalette() : m_background(Qt::white), m_text(Qt::black) {}
 
QColor background() const { return m_background; }
void setBackground(const QColor &c) {
if (c != m_background) {
m_background = c;
emit backgroundChanged();
}
}
 
QColor text() const { return m_text; }
void setText(const QColor &c) {
if (c != m_text) {
m_text = c;
emit textChanged();
}
}
 
signals:
void textChanged();
void backgroundChanged();
 
private:
QColor m_background;
QColor m_text;
};
 
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
 
QDeclarativeView view;
view.rootContext()->setContextProperty("palette", new CustomPalette);
 
view.setSource(QUrl::fromLocalFile("main.qml"));
view.show();
 
return app.exec();
}

下面的QML文件使用了palette对象及它的属性来设置背景和文字颜色。当窗口被点击时,palette的颜色将被改变,窗口文本也会被相应的更新:

 import QtQuick 1.0
 
Rectangle {
width: 240
height: 320
color: palette.background
 
Text {
anchors.centerIn: parent
color: palette.text
text: "Click me to change color!"
}
 
MouseArea {
anchors.fill: parent
onClicked: {
palette.text = "blue";
}
}
}

在这个例子中,当检测到C++属性值(CustomPalette的文本)改变时,该属性必须有一个相应的NOTIFY信号,当属性值改变时发送NOTIFY信号。实现的时候需要注意,仅当属性值改变时才发送信号,从而避免发生死循环。访问一个绑定的属性时,如果没有NOTIFY信号将会导致QML产生一个运行时的警告。

动态结构数据(Dynamic Structured Data)

如果一个应用程序在编译期具有很多QObject类型的动态结构化数据,可以使用QDeclarativePropertyMap在运行期动态的创建这些结构化数据。

在QML中调用C++方法

QML中可以调用QObject及其派生类对象中的public slot的方法或标记为Q_INVOKABLE的方法。

上述的C++方法可以具有参数和返回值,QML支持下列数据类型:

   * bool
   * unsigned int, int
   * float, double, qreal
   * QString
   * QUrl
   * QColor
   * QDateQTimeQDateTime
   * QPointQPointF
   * QSize, QSizeF
   * QRectQRectF
   * QVariant

下面的例子演示了当MouseArea被点击时,触发“Stopwatch”对象的start()/stop():

// main.cpp
 
class Stopwatch : public QObject
{
Q_OBJECT
public:
Stopwatch();
 
Q_INVOKABLE bool isRunning() const;
 
public slots:
void start();
void stop();
 
private:
bool m_running;
};
 
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
 
QDeclarativeView view;
view.rootContext()->setContextProperty("stopwatch",
new Stopwatch);
 
view.setSource(QUrl::fromLocalFile("main.qml"));
view.show();
 
return app.exec();
}
// main.qml
 
import QtQuick 1.0
 
Rectangle {
width: 300
height: 300
 
MouseArea {
anchors.fill: parent
onClicked: {
if (stopwatch.isRunning())
stopwatch.stop()
else
stopwatch.start();
}
}
}

请注意,在这个特殊的例子中,有一个更好的方法来达到同样的结果——main.qml中可以用一个“运行中“属性(property),更漂亮的QML代码如下:

 // main.qml
import QtQuick 1.0
 
Rectangle {
MouseArea {
anchors.fill: parent
onClicked: stopwatch.running = !stopwatch.running
}
}

此外,还可以调用functions declared in QML from C++描述的方法。

网络组件(Network Components)

如果传递给QDeclarativeComponent一个网络资源,或者QML document中引用了网络资源,QDeclarativeComponent会在创建对象之前先获取网络资源数据。在这种情况下QDeclarativeComponent将有一个加载状态(Loading status)。应用程序将一直等待(在调用QDeclarativeComponent::create()之前),直到组件准备完毕。

下面的例子演示了如何加载一个网络QML文件资源。QDeclarativeComponent创建后,先检查组件是否正在加载,如果正在加载则连接QDeclarativeComponent::statusChanged()信号,否则直接调用continueLoading()方法。虽然在这个例子里已经知道URL在远程,但这个检查还是必须的,这样可以在组件已经缓存了该URL的情况下,直接创建组该件。

 MyApplication::MyApplication()
{
// ...
component = new QDeclarativeComponent(engine, QUrl("http://www.example.com/main.qml"));
if (component->isLoading())
QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
this, SLOT(continueLoading()));
else
continueLoading();
}
 
void MyApplication::continueLoading()
{
if (component->isError()) {
qWarning() << component->errors();
} else {
QObject *myObject = component->create();
}
}

Qt资源(Qt Resources)

QML可以通过qrc:URL从Qt资源系统(Qt Resource System)中加载,例如:

[project/example.qrc]

 <!DOCTYPE RCC>
<RCC version="1.0">
 
<qresource prefix="/">
<file>main.qml</file>
<file>images/background.png</file>
</qresource>
 
</RCC>


[project/project.pro]

 QT += declarative
 
SOURCES += main.cpp
RESOURCES += example.qrc

[project/main.cpp]

 int main(int argc, char *argv[])
{
QApplication app(argc, argv);
 
QDeclarativeView view;
view.setSource(QUrl("qrc:/main.qml"));
view.show();
 
return app.exec();
}

[project/main.qml]

 import QtQuick 1.0
 
Image {
source: "images/background.png"
}

注意:QML中无法直接访问资源系统。如果主QML文件作为资源加载,主QML文件中的所有指定相对路径的文件都将从资源系统中加载。如果主QML文件没有作为资源加载,那么资源系统中的文件无法在QML中访问。

相关链接

This page was last modified on 11 October 2012, at 01:19.
248 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×