zoukankan      html  css  js  c++  java
  • QML基础——在C++程序中使用QML

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

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

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

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

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

    基本用法

    若想将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 {
    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属性。

    结构化数据(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 {
    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
    * QDate,QTime,QDateTime
    * QPoint,QPointF
    * QSize, QSizeF
    * QRect,QRectF
    * 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 {
    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中访问。

  • 相关阅读:
    我的2020书单
    记录一次克隆硬盘的经历
    npm简单介绍
    批量处理Excel从格式xls到xlsx
    SQL经典实例笔记
    在字符串中找出连续最长的数字串
    将数字转化成字符串
    寄存器位读写,结构体位域定义,位域操作,位操作
    android C/C++ source files 全局宏定义 .
    android2.3 -添加自定义按键:作唤醒功能 .
  • 原文地址:https://www.cnblogs.com/hicjiajia/p/2332266.html
Copyright © 2011-2022 走看看