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

11 篇文章 0 订阅
1 篇文章 0 订阅

 

转自: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()来访问:

 
  1. // Using QDeclarativeComponent

  2.  QDeclarativeEngine engine;

  3.  QDeclarativeComponentcomponent(&engine,

  4.          QUrl::fromLocalFile("MyItem.qml"));

  5.  QObject *object = component.create();

  6.  ...

  7.  delete object;

 
  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代码调用对象实例的方法:

 
  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类:

 
  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引擎后:

 

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"
     }
 }

 

 

 
 
  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)
         }
     }
 }

 

 

 
 
  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")
     }
 }

 

 

 
 
  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)
 }

 

 

 
  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!")
     }
 }

 

 

 
  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属性:

 
  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成员变量值.直接修改成员变量值是不明智的:

 
  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"
     }
 }

 

 

 
  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])
         }
     }
 }

 

 

 
 
  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:

 
  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枚举类型:

 
  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资源系统的应用程序包.目录结构如下:

 
  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资源文件中指定:

 
  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):

 
  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 文件:

 
  1.  QT += declarative

  2.  
  3.  SOURCES += main.cpp

  4.  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Qt C++使用文路径到QML,可以通过以下步骤实现: 1. 首先,确保项目的.pro文件添加了对文路径的支持。在.pro文件添加如下代码: ``` # 用于支持文路径 CONFIG += utf8_sources ``` 2. 在Qt C++使用QDir类来处理文路径。使用QDir的toNativeSeparators()方法将文路径转换为本地路径。例如: ``` QString chinesePath = "文路径"; QString nativePath = QDir::toNativeSeparators(chinesePath); ``` 3. 在要将文路径传递给QML的地方,将转换后的本地路径传递给QML的属性或绑定。例如,将转换后的本地路径传递给一个名为"sourcePath"的QML属性: ``` QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("sourcePath", nativePath); ``` 4. 在QML,通过使用转换后的本地路径加载和处理文路径。例如,使用Image元素加载图像并使用转换后的本地路径: ``` Image { source: sourcePath } ``` 通过以上步骤,您可以在Qt C++使用文路径到QML。请务必处理好转换后的本地路径,以确保正确加载和处理文路径。 ### 回答2: 在Qt C++,要将文路径传递给QML文件,可以通过以下步骤实现。 首先,确保你的Qt版本支持文路径。然后,创建一个QML文件,并使用QQuickView或QQuickWidget加载它。 接下来,在你的QML文件,可以通过使用QString类型的属性来接收文路径。例如,在QML文件添加一个属性: property string chinesePath: "" 然后,你可以在C++代码,通过setProperty()函数将文路径传递给QML文件的属性。例如,如果你有一个QString类型的变量chinesePath,你可以这样传递它的值: viewer->rootObject()->setProperty("chinesePath", chinesePath); 此外,在QML文件,你可以使用Qt提供的FileDialog来选择文路径。例如,你可以在QML添加一个按钮,当点击时,弹出文件选择对话框,并将选择的路径传递给上述的chinesePath属性。 FileDialog { id: fileDialog // 设置文件选择对话框属性 title: "选择文件" folder: Qt.resolvedUrl(".") // 设置默认打开目录为当前目录 selectFolder: true // 打开目录选择模式 onAccepted: { chinesePath = fileDialog.fileUrl.toString().substring(8); // 去除file:/// } } 最后,在QML,你可以使用这个属性来操作文路径,例如,加载一个图片: Image { source: chinesePath } 总的来说,要将文路径传递给QML文件,你需要在C++QML之间传递文路径的字符串,并在QML使用这个字符串来操作文路径。通过这种方式,你就可以在Qt C++实现文路径到QML的传递了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值