C++程序中使用QML绑定机制

原文地址:http://doc.qt.digia.com/4.7-snapshot/qtbinding.html
QML被定为一种可容易使用C++扩展,并可扩展C++的语言.使用Qt Declarative模块中的类可在C++中加载和操作QML中的组件,通过Qt的元对象系统,QML和C++对象可轻易的使用信号和槽机制进行通信.此外,QML插件可以创建发布可重用QML组件.

你可能有很多种理由要将QML和C++混合使用.如:

  • 使用C++源码中的函数/功能 (如使用基于Qt的C++数据模型,或调用三方C++库中的函数)
  • 访问Qt Declarative模块中的函数/功能 (如使用QDeclarativeImageProvider动态创建图像)
  • 创建QML组件(用于自己的项目或发布给其他人使用)

要使用Qt Declarative模块,必须包含和链接相应的模块,请见module index page.Qt Declarative UI Runtime 文档展示如何使用这个模块创建基于C++的应用程序.

核心模块类

Qt Declarative模块提供了一组C++ API用于在C++中扩展QML应用程序,并可将QML嵌入到C++应用程序中.Qt Declarative模块中有几个核心类为实现这个目标提供了必要的支持:

 QDeclarativeEngine 用来为其中的所有QML组件实例配置全局选项:如用于网络通信的QNetworkAccessManager和用于持久化存储的文件路径等.

QDeclarativeComponent 用于加载QML文档.每个QDeclarativeComponent 实例代表一个单一文档.组件可使用代表QML文档的URL或文件路径,QML代码来创建.组件实例化是通过QDeclarativeComponent::create()方法完成的,如下所示:

 QDeclarativeEngine engine;
 QDeclarativeComponent component(&engine, QUrl::fromLocalFile("MyRectangle.qml"));
 QObject *rectangleInstance = component.create();

 // ...
 delete rectangleInstance;

QML文档也可使用QDeclarativeView来加载.这个类为基于QWidget的视图加载QML组件提供了方便.(向基于QWidget的应用程序中整合QML的其他方法请见Integrating QML Code with existing Qt UI code)

QML与C++结合的方式

使用C++扩展QML应用程序有很多种方式.例如::

  • 在C++中加载QML组件并进行操作(可操作其子元素)
  • 直接将C++对象及其属性嵌入到QML组件中(例如,在QML中调用指定的C++对象,或使用数据集来模拟一个列表模型)
  • 定义新的QML元素(QObject继承)并可在QML代码中直接创建

这些方式在下面做展示.当然这些方式相互间不冲突,在应用程序中可根据需要组合使用.

在C++中加载QML组件

QML文档可使用QDeclarativeComponent 或QDeclarativeView来加载.QDeclarativeComponent 将QML组件作为一个C++对象加载;QDeclarativeView 也是这样的,但他将QML组件直接加载到一个QGraphicsView中. 可方便的将QML组件加载到一个基于QWidget应用程序中.

例如,有如下所示的一个MyItem.qml文件:

 import QtQuick 1.0

 Item {
     width: 100; height: 100
 }

下面的C++代码将这个QML文档加载到QDeclarativeComponent 或QDeclarativeView .使用QDeclarativeComponent 需要调用QDeclarativeComponent::create()来创建一个新的组件实例,而QDeclarativeView 自动创建组件实例,可通过QDeclarativeView::rootObject()来访问:

[cpp]  view plain copy
  1. // Using QDeclarativeComponent  
  2.  QDeclarativeEngine engine;  
  3.  QDeclarativeComponent component(&engine,  
  4.          QUrl::fromLocalFile("MyItem.qml"));  
  5.  QObject *object = component.create();  
  6.  ...  
  7.  delete object; <span class="comment"></span>  
[cpp]  view plain copy
  1.  // Using QDeclarativeView  
  2.  QDeclarativeView view;  
  3.  view.setSource(QUrl::fromLocalFile("MyItem.qml"));  
  4.  view.show();  
  5.  QObject *object = view.rootObject();  

这样就创建了一个MyItem.qml组件的实例--object.可使用QObject::setProperty() 或QDeclarativeProperty修改项目的属性:

 object->setProperty("width", 500);
 QDeclarativeProperty(object, "width").write(500);

当然,也可将对象转换为其实际类型,以便于在编译时期安全的调用方法.本例中基于MyItem.qml的对象是一个Item,由QDeclarativeItem 类来定义:

 QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(object);
 item->setWidth(500);

也可使用QMetaObject::invokeMethod() 和QObject::connect()来连接或调用定义在组件中的信号或函数.更多信息见Exchanging data between QML and C++ .

定位子对象

QML组件本质上是一个具有兄弟和子节点的对象树.可使用QObject::findChild()传递一个对象名称获取QML组件的子对象.例如MyItem.qml中的根对象具有一个Rectangle子元素:

 import QtQuick 1.0

 Item {
     width: 100; height: 100

     Rectangle {
         anchors.fill: parent
         objectName: "rect"
     }
 }

可这样获取子对象:

 QObject *rect = object->findChild<QObject*>("rect");
 if (rect)
     rect->setProperty("color", "red");

如果objectName被用于ListView,Repeater代理,或其他生成多个实例的代理上,将会有多个子对象具有相同的名称(objectName).这时,使用QObject::findChildren()获取所有叫做objectName的子元素.

警告: 由于这种方法可以在C++中获取并操作对象树中内部的QML元素,除了测试和建立原型外我们不建议采用这种方式.QML和C++整合在一起的一个优势就是将QML的用户界面与C++逻辑和数据集相隔离,如果在C++中直接获取并操作QML对象中的内部组件会打破这个策略. 这将使开发变得困难,如更改了QML视图,新的组件中不含objectName子元素,会发生错误.最好的情况是C++实现对QML用户界面实现和内部组成QML对象树不做任何假设.

在QML组件中嵌入C++对象

当在C++应用程序中加载QML场景时,将C++数据嵌入到QML对象中是很有帮助的.QDeclarativeContext 可以向QML组件暴漏数据,将数据从C++注入到QML中.

例如,下面的QML项中有一个currentDateTime值,但并没有在这个上下文中声明:

 // MyItem.qml
 import QtQuick 1.0

 Text { text: currentDateTime }

这个currentDateTime值可以直接由加载QML组件的C++应用程序使用QDeclarativeContext::setContextProperty()进行设置:

 QDeclarativeView view;
 view.rootContext()->setContextProperty("currentDateTime", QDateTime::currentDateTime());
 view.setSource(QUrl::fromLocalFile("MyItem.qml"));
 view.show();

上下文属性可以存储为QVariant或者QObject*类型.这意味着自定义的C++对象也可以使用这种方式注入,而且可以直接在QML中读取或修改这些对象.我们将上例中的QDateTime值修改为一个嵌入的QObject实例,让QML代码调用对象实例的方法:

[cpp]  view plain copy
  1. class ApplicationData : public QObject  
  2.  {  
  3.      Q_OBJECT  
  4.  public:  
  5.      Q_INVOKABLE QDateTime getCurrentDateTime() const {  
  6.          return QDateTime::currentDateTime();  
  7.      }  
  8.  };  
  9.   
  10.  int main(int argc, char *argv[]) {  
  11.      QApplication app(argc, argv);  
  12.   
  13.      QDeclarativeView view;  
  14.   
  15.      ApplicationData data;  
  16.      view.rootContext()->setContextProperty("applicationData", &data);  
  17.   
  18.      view.setSource(QUrl::fromLocalFile("MyItem.qml"));  
  19.      view.show();  
  20.   
  21.      return app.exec();  
  22.  }   

// MyItem.qml
import QtQuick 1.0

Text { text: applicationData.getCurrentDateTime() }
(注意C++向QML返回的date/time值可使用 Qt.formatDateTime() 及相关函数进行格式化.)

如果QML需要接收上下文的信号,可使用Connections元素进行连接.例如,如果ApplicationData有一个叫做dataChanged()的信号,这个信号可以使用Connections对象连接到一个信号处理器上:

 Text {
     text: applicationData.getCurrentDateTime()

     Connections {
         target: applicationData
         onDataChanged: console.log("The application data changed!")
     }
 }

上下文属性在QML视图中使用基于C++的数据模型时很有用.见String ListModel,Object ListModel 和AbstractItemModel 模型,展示了在QML视图中使用QStringListModel模型,基于QObjectList的模型 和QAbstractItemModel模型 .

更多信息见QDeclarativeContext .

定义新的QML元素

QML中可以定义新的QML元素,同样也可在C++中定义;事实上很多QML元素都是通过C++类实现的.当使用这些元素创建一个QML对象时,只是简单的创建了这个基于QObject的C++类的实例,并设置了属性.

要创建与Qt Quick元素兼容的项,需要使用QDeclarativeItem作为基类.然后实现自绘和像其他QGraphicsObject一样的功能.注意在QDeclarativeItem中默认设置了QGraphicsItem::ItemHasNoContents,因为其不绘制任何东西;如果项目需要绘制则需要清除这个标志(相反的情况是只作为输入处理和逻辑分组的情况).

例如,下面是一个带有image属性的ImageViewer类:

[cpp]  view plain copy
  1.  #include <QtCore>  
  2.  #include <QtDeclarative>  
  3.   
  4.  class ImageViewer : public QDeclarativeItem  
  5.  {  
  6.      Q_OBJECT  
  7.      Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)  
  8.   
  9.  public:  
  10.      void setImage(const QUrl &url);  
  11.      QUrl image() const;  
  12.   
  13.  signals:  
  14.      void imageChanged();  
  15.  };  

除了从QDeclarativeItem继承外,这都可作为与QML无关的常规类.然而,使用qmlRegisterType()注册到QML引擎后:

[cpp]  view plain copy
  1. qmlRegisterType<ImageViewer>("MyLibrary", 1, 0, "ImageViewer");  

加载到C++应用程序或插件中的QML代码就可以操作ImageViewer对象:

import MyLibrary 1.0

ImageViewer { image: "smile.png" }

这里建议不要使用QDeclarativeItem文档指定属性之外的功能.这是因为GraphicsView后台依赖QML的实现细节,因此QtQuick项可再向底层移动,在QML角度上可以应用但不能修改.要最小化自定义可视项的可移植要求,就应尽量坚持使用QDeclarativeItem文档标记的属性.从QDeclarativeItem中继承但没有文档化的属性都是与实现细节相关的;他们不受官方支持可能在相关的发布版本中被去掉.

注意自定义的C++类不必从QDeclarativeItem继承;只有在需要显示时才是必须的.如果项不可见,可从QObject继承.

创建QML元素的更多信息,见Writing QML extensions with C++ 和Extending QML Functionalities using C++ .

在QML和C++之间交换数据

QML和C++对象之间可通过信号槽,属性修改等机制进行通信.对于一个C++对象,任何暴露在Qt的元对象系统中的数据--属性,信号,槽和使用Q_INVOKABLE标记的方法都可在QML中访问.在QML端,所有QML对象的数据都可在Qt元对象系统和C++中访问.

调用函数

QML函数可在C++中调用,反之亦然.

所有的QML函数都被暴漏在了元数据系统中,并可通过QMetaObject::invokeMethod()调用.C++应用程序调用QML函数:

// MyItem.qml
 import QtQuick 1.0

 Item {
     function myQmlFunction(msg) {
         console.log("Got message:", msg)
         return "some return value"
     }
 }

 
[cpp]  view plain copy
  1.  // main.cpp  
  2.  QDeclarativeEngine engine;  
  3.  QDeclarativeComponent component(&engine, "MyItem.qml");  
  4.  QObject *object = component.create();  
  5.   
  6.  QVariant returnedValue;  
  7.  QVariant msg = "Hello from C++";  
  8.  QMetaObject::invokeMethod(object, "myQmlFunction",  
  9.          Q_RETURN_ARG(QVariant, returnedValue),  
  10.          Q_ARG(QVariant, msg));  
  11.   
  12.  qDebug() << "QML function returned:" << returnedValue.toString();  
  13.  delete object;  

注意QMetaObject::invokeMethod()中Q_RETURN_ARG() 和Q_ARG()的参数必须指定为QVariant类型,这是QML函数和返回值的通用数据类型.

在QML中调用C++函数,函数必须是Qt的槽或标记了Q_INVOKABLE宏的函数,才能在QML中访问.下面范例中,QML代码调用了(使用QDeclarativeContext::setContextProperty()设置到QML中的)myObject对象的方法:

 // MyItem.qml
 import QtQuick 1.0

 Item {
     width: 100; height: 100

     MouseArea {
         anchors.fill: parent
         onClicked: {
             myObject.cppMethod("Hello from QML")
             myObject.cppSlot(12345)
         }
     }
 }

[cpp]  view plain copy
  1.  class MyClass : public QObject  
  2.  {  
  3.      Q_OBJECT  
  4.  public:  
  5.      Q_INVOKABLE void cppMethod(const QString &msg) {  
  6.          qDebug() << "Called the C++ method with" << msg;  
  7.      }  
  8.   
  9.  public slots:  
  10.      void cppSlot(int number) {  
  11.          qDebug() << "Called the C++ slot with" << number;  
  12.      }  
  13.  };  
  14.   
  15.  int main(int argc, char *argv[]) {  
  16.      QApplication app(argc, argv);  
  17.   
  18.      QDeclarativeView view;  
  19.      MyClass myClass;  
  20.      view.rootContext()->setContextProperty("myObject", &myClass);  
  21.   
  22.      view.setSource(QUrl::fromLocalFile("MyItem.qml"));  
  23.      view.show();  
  24.   
  25.      return app.exec();  
  26.  }  

QML支持调用C++的重载函数.如果C++中有多个同名不同参的函数,将根据参数数量和类型调用正确的函数.

接收信号

所有QML信号都可在C++中访问,像任何标准的Qt C++信号一样可使用QObject::connect()进行连接.相反,任何C++信号都可被QML对象的信号处理函数接收.

下面的QML组件具有一个叫做qmlSignal的信号.这个信号使用QObject::connect()连接到了一个C++对象的槽上,当qmlSignal触发时会调用cppSlot()函数:

 // MyItem.qml
 import QtQuick 1.0

 Item {
     id: item
     width: 100; height: 100

     signal qmlSignal(string msg)

     MouseArea {
         anchors.fill: parent
         onClicked: item.qmlSignal("Hello from QML")
     }
 }

[cpp]  view plain copy
  1.  class MyClass : public QObject  
  2.  {  
  3.      Q_OBJECT  
  4.  public slots:  
  5.      void cppSlot(const QString &msg) {  
  6.          qDebug() << "Called the C++ slot with message:" << msg;  
  7.      }  
  8.  };  
  9.   
  10.  int main(int argc, char *argv[]) {  
  11.      QApplication app(argc, argv);  
  12.   
  13.      QDeclarativeView view(QUrl::fromLocalFile("MyItem.qml"));  
  14.      QObject *item = view.rootObject();  
  15.   
  16.      MyClass myClass;  
  17.      QObject::connect(item, SIGNAL(qmlSignal(QString)),  
  18.                       &myClass, SLOT(cppSlot(QString)));  
  19.   
  20.      view.show();  
  21.      return app.exec();  
  22.  }  

要在QML中连接Qt C++的信号,使用on<SignalName>语法访问信号句柄.如果C++对象可直接在QML中创建(见上面的Defining new QML elements),信号处理函数可在对象定义时指定.在下面例子中,QML代码创建了一个ImageViewer对象,C++对象的imageChanged和loadingError信号连接到QML中的onImageChanged和onLoadingError信号处理函数:

 ImageViewer {
     onImageChanged: console.log("Image changed!")
     onLoadingError: console.log("Image failed to load:", errorMsg)
 }

[cpp]  view plain copy
  1.  class ImageViewer : public QDeclarativeItem  
  2.  {  
  3.      Q_OBJECT  
  4.      Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)  
  5.  public:  
  6.      ...  
  7.  signals:  
  8.      void imageChanged();  
  9.      void loadingError(const QString &errorMsg);  
  10.  };  

(注意如果信号被声明为属性的NOTIFY信号,QML就允许使用on<Property>Changed句柄访问这个信号,即使信号的名称不是<Property>Changed.上例中,如果将imageChanged信号改为imageModified,onImageChanged信号处理函数还是会被调用的.)

然而对于不是从QML中创建的对象,QML中的元素只能访问已创建的对象--例如如果对象是通过QDeclarativeContext::setContextProperty()设置的--就可使用Connections元素来设置信号处理函数了:

// MyItem.qml
 import QtQuick 1.0

 Item {
     Connections {
         target: imageViewer
         onImageChanged: console.log("Image has changed!")
     }
 }

[cpp]  view plain copy
  1.  ImageViewer viewer;  
  2.   
  3.  QDeclarativeView view;  
  4.  view.rootContext()->setContextProperty("imageViewer", &viewer);  
  5.   
  6.  view.setSource(QUrl::fromLocalFile("MyItem.qml"));  
  7.  view.show();  
 

C++信号可以使用枚举值作为参数,枚举定义在类中随信号触发而传递,这个枚举必须使用Q_ENUMS宏注册.见Using enumerations of a custom type.

修改属性

C ++中可以访问QML对象的所有属性.对如下QML对象:

 // MyItem.qml
 import QtQuick 1.0

 Item {
     property int someNumber: 100
 }

使用QDeclarativeProperty, 或QObject::setProperty() 和QObject::property()可以设置和读取someNumber属性:

[cpp]  view plain copy
  1.  QDeclarativeEngine engine;  
  2.  QDeclarativeComponent component(&engine, "MyItem.qml");  
  3.  QObject *object = component.create();  
  4.   
  5.  qDebug() << "Property value:" << QDeclarativeProperty::read(object, "someNumber").toInt();  
  6.  QDeclarativeProperty::write(object, "someNumber", 5000);  
  7.   
  8.  qDebug() << "Property value:" << object->property("someNumber").toInt();  
  9.  object->setProperty("someNumber", 100);  

你应该总使用QObject::setProperty(),QDeclarativeProperty 或QMetaProperty::write()修改QML属性值,使QML引擎知道属性已经被修改.例如,假设有一个自定义的元素PushButton,带有一个buttonText属性,反映内部的m_buttonText成员变量值.直接修改成员变量值是不明智的:

[cpp]  view plain copy
  1.  // BAD!  
  2.  QDeclarativeComponent component(engine, "MyButton.qml");  
  3.  PushButton *button = qobject_cast<PushButton*>(component.create());  
  4.  button->m_buttonText = "Click me";  

由于直接修改了成员变量的值,越过了Qt的元对象系统,QML引擎就无法知道值被修改过.这样绑定到buttonText的属性就不会更新,任何onButtonTextChanged处理函数都不会被调用.

任何使用Q_PROPERTY宏声明的Qt属性都可在QML中访问.下面修改本文档前面例子,ApplicationData类具有一个backgroundColor属性.这个属性可在QML中进行读写:

// MyItem.qml
 import QtQuick 1.0

 Rectangle {
     width: 100; height: 100
     color: applicationData.backgroundColor

     MouseArea {
         anchors.fill: parent
         onClicked: applicationData.backgroundColor = "red"
     }
 }

[cpp]  view plain copy
  1.  class ApplicationData : public QObject  
  2.  {  
  3.      Q_OBJECT  
  4.      Q_PROPERTY(QColor backgroundColor  
  5.              READ backgroundColor  
  6.              WRITE setBackgroundColor  
  7.              NOTIFY backgroundColorChanged)  
  8.   
  9.  public:  
  10.      void setBackgroundColor(const QColor &c) {  
  11.          if (c != m_color) {  
  12.              m_color = c;  
  13.              emit backgroundColorChanged();  
  14.          }  
  15.      }  
  16.   
  17.      QColor backgroundColor() const {  
  18.          return m_color;  
  19.      }  
  20.   
  21.  signals:  
  22.      void backgroundColorChanged();  
  23.   
  24.  private:  
  25.      QColor m_color;  
  26.  };  
 

注意backgroundColorChanged被标记为backgroundColor属性的NOTIFY信号.如果Qt属性没有相关的NOTIFY信号,属性就不能用于QML的属性绑定,因为当属性值被修改时QML引擎不会得到通知.如果在QML中使用自定义类型,确保属性具有NOTIFY信号,以便于用于属性绑定中.

在QML中使用QML属性的更多信息见Tutorial: Writing QML extensions with C++ .

支持的数据类型

用于QML中的任何C++数据--自定义属性,或信号和函数的参数,QML都必须支持其类型.

默认QML支持如下数据类型:

为了可以在QML创建和使用自定义C++类型,C++类必须使用qmlRegisterType()注册为QML类型,请见上面的Defining new QML elements 小节.

JavaScript数组和对象

QML内建支持在QVariantList和JavaScript数组之间,QVariantMap和JavaScript对象间的转换.

例如,如下定义在QML中的函数需要两个参数,一个数组一个对象,使用标准的JavaScript语法访问数组和对象输出其中的内容.C++代码调用了这个函数,传递QVariantList 和QVariantMap参数,将自动转换为JavaScript的数组和对象:

 // MyItem.qml
 Item {
     function readValues(anArray, anObject) {
         for (var i=0; i<anArray.length; i++)
             console.log("Array item:", anArray[i])

         for (var prop in anObject) {
             console.log("Object item:", prop, "=", anObject[prop])
         }
     }
 }

[cpp]  view plain copy
  1.  // C++  
  2.  QDeclarativeView view(QUrl::fromLocalFile("MyItem.qml"));  
  3.   
  4.  QVariantList list;  
  5.  list << 10 << Qt::green << "bottles";  
  6.   
  7.  QVariantMap map;  
  8.  map.insert("language""QML");  
  9.  map.insert("released", QDate(2010, 9, 21));  
  10.   
  11.  QMetaObject::invokeMethod(view.rootObject(), "readValues",  
  12.          Q_ARG(QVariant, QVariant::fromValue(list)),  
  13.          Q_ARG(QVariant, QVariant::fromValue(map)));  

This produces output like:

[cpp]  view plain copy
  1.  Array item: 10  
  2.  Array item: #00ff00  
  3.  Array item: bottles  
  4.  Object item: language = QML  
  5.  Object item: released = Tue Sep 21 2010 00:00:00 GMT+1000 (EST)  

同样,如果C++定义了QVariantList 或QVariantMap 类型的属性或函数参数,在QML访问时,可创建JavaScript的数组或对象,并自动被转换为QVariantList 或QVariantMap 传递给C++.

使用自定义枚举类型

要在自定义C++组件中使用枚举,枚举类型必须使用Q_ENUMS宏注册到Qt的元对象系统.例如,如下C++类型具有一个Status枚举类型:

[cpp]  view plain copy
  1.  class ImageViewer : public QDeclarativeItem  
  2.  {  
  3.      Q_OBJECT  
  4.      Q_ENUMS(Status)  
  5.      Q_PROPERTY(Status status READ status NOTIFY statusChanged)  
  6.  public:  
  7.      enum Status {  
  8.          Ready,  
  9.          Loading,  
  10.          Error  
  11.      };  
  12.   
  13.      Status status() const;  
  14.  signals:  
  15.      void statusChanged();  
  16.  };  

假设ImageViewer类已经使用qmlRegisterType()进行注册,现在其Status枚举可用在QML中:

 ImageViewer {
     onStatusChanged: {
         if (status == ImageViewer.Ready)
             console.log("Image viewer is ready!")
     }
 }

要使用内置的枚举,C++类必须注册到QML中.如果C++类型不可实例化,可使用qmlRegisterUncreatableType()注册.在QML中枚举值其首字母必须大写.

更多信息见Writing QML extensions with C++ 和Extending QML Functionalities using C++.

枚举值作为信号参数

C++信号可以向QML中传递一个枚举类型参数,假设枚举和信号定义在同一个类中,或枚举值定义在Qt命名空间(Qt Namespace)中.

此外,如果C++信号带有一个枚举参数,应该使用connect()函数与QML中的函数相关联,枚举类型必须使用qRegisterMetaType()注册.

对于QML信号,作为信号参数的枚举值使用int类型替代:

 ImageViewer {
     signal someOtherSignal(int statusValue)

     Component.onCompleted: {
         someOtherSignal(ImageViewer.Loading)
     }
 }

从字符串做自动类型转换

为了方便,在QML中一些基本类型的值可使用格式化字符串指定,便于在QML中向C++传递简单的值.

TypeString formatExample
QColor颜色名称, "#RRGGBB", "#RRGGBBAA""red", "#ff0000", "#ff000000"
QDate"YYYY-MM-DD""2010-05-31"
QPoint"x,y""10,20"
QRect"x,y,宽x高""50,50,100x100"
QSize"宽x高""100x200"
QTime"hh:mm:ss""14:22:55"
QUrlURL字符串"http://www.example.com"
QVector3D"x,y,z""0,1,0"
枚举值枚举值名称"AlignRight"

(更多字符串格式和类型见basic type documentation.)

这些字符串格式用于设置QML属性值和向C++函数传递参数.本文档中有很多范例进行演示;在上面的范例中,ApplicationData类有一个QColor类型的backgroundColor属性,在QML中使用字符串"red"而不是一个QColor对象进行赋值.

如果喜欢使用显式类型赋值,Qt对象提供了便利的全局函数来创建对象的值.例如Qt.rgba()创建一个基于RGBA的QColor值.这个函数返回的QColor类型的值可用于设置QColor类型的属性,或调用需要QColor类型参数的C++函数.

创建QML插件

Qt Declarative模块包含一个QDeclarativeExtensionPlugin类,这个抽象类用于创建QML插件.可在QML应用程序中动态加载QML扩展类型.

更多信息见QDeclarativeExtensionPlugin 文档和How to Create Qt Plugins .

使用Qt资源系统管理资源文件

Qt resource system 可将资源文件存储在二进制可执行文件中.这对创建QML/C++联合的应用程序很有帮助,可通过资源系统的URI(像其他图片和声音资源文件一样)调度访问QML文件,而不是使用相对或绝对文件系统路径.注意如果使用资源系统,当QML资源文件被修改后必须重新编译可执行应用程序,以便于更新包中的资源.

要在QML/C++应用程序中使用资源系统:

  • 创建一个.qrc资源集合文件,以XML格式例举资源文件
  • 在C++中,使用:/prefix或qrc调度URL加载主QML文件资源

这样做后,QML中所有已相对路径指定的文件都从资源文件中加载.使用资源系统完全对QML层透明;即QML代码可以用相对路径来访问资源文件,而不带有qrc调度.这个调度(qrc)只用于在C++中引用资源文件.

这是使用Qt资源系统的应用程序包.目录结构如下:

[cpp]  view plain copy
  1.  project  
  2.      |- example.qrc  
  3.      |- main.qml  
  4.      |- images  
  5.          |- background.png  
  6.      |- main.cpp  
  7.      |- project.pro  

main.qml 和 background.png 文件作为资源文件打包.这在example.qrc资源文件中指定:

[cpp]  view plain copy
  1.  <!DOCTYPE RCC>  
  2.  <RCC version="1.0">  
  3.   
  4.  <qresource prefix="/">  
  5.      <file>main.qml</file>  
  6.      <file>images/background.png</file>  
  7.  </qresource>  
  8.   
  9.  </RCC>  

由于background.png 是一个资源文件,main.qml可在example.qrc中使用的相当路径引用它:

 // main.qml
 import QtQuick 1.0

 Image { source: "images/background.png" }

要使QML文件正确的定位资源文件,main.cpp加载主QML文件--main.qml,访问资源文件需要使用qrc调度(scheme):

[cpp]  view plain copy
  1.  int main(int argc, char *argv[])  
  2.  {  
  3.      QApplication app(argc, argv);  
  4.   
  5.      QDeclarativeView view;  
  6.      view.setSource(QUrl("qrc:/main.qml"));  
  7.      view.show();  
  8.   
  9.      return app.exec();  
  10.  }  

最后在project.pro中将RESOURCES 变量设置为用来构建应用程序资源的example.qrc 文件:

[cpp]  view plain copy
  1.  QT += declarative  
  2.   
  3.  SOURCES += main.cpp  
  4.  RESOURCES += example.qrc 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值