柚子快报邀请码778899分享:qt QML笔记八

http://yzkb.51969.com/

QML与C++交互 QML中调用C++功能、使用QML或者Quick中的C++接口、使用C++实现自定义的QML对象 注: 只有QObject的派生类才能与QML交互 QML引擎集成Qt元对象系统,QObject的派生子类的属性、方法、信号都可以在QML中访问 C++类可以被注册为一个QML实例 C++类可以被注册为一个单例类型,可在QML中导入单例对象 C++类实例可以作为上下文属性或上下文对象嵌入到QML中

1.QML运行时C++类

Qt QML模块实现了QML框架的C++类,客户端可以使用这些类与QML运行时进行交互 以C++为切入点的QML客户端启动时会: 1.客户端初始化一个QQmlEngine 2.使用QQmlComponent对象加载QML文件 3.QML引擎提供一个默认的QQmlContext对象作为顶层执行上下文,用来执行QML文件中定义的函数、表达式;通过QQmlEngine::rootContext获取该上下文 4.若加载QML文件没错时,QML文件的对象将使用QQmlComponent对象的create()创建。 5.所有对象创建完毕,客户端将控制权交给应用程序的事件循环

2.QQmlEngine 2.1提供一个QML引擎,管理qml文件的对象层次结构 2.2提供一个默认上下文,即根上下文,代表执行环境,保证在需要时对象属性可以被更新 2.3允许将全局设置应用到它管理的所有对象

3.QQmlApplicationEngine

是 QQmlEngine的子类,结合了QQmlEngine、QQmlComponent功能 更简便的实现从一个单一的qml文件加载应用程序 提供一些核心应用程序功能,,一般由C++控制 例如: QQmlQpplicationEngine engine; engine.load(QStringLiteral(“qrc:/main.qml”)) 一般QQmlQpplicationEngine加载的qml文件其根对象应该是widnow或者ApplicationWindow,不然无法显示 若要加载根不是window或其子类的qml文件时使用 QQuickView* view=new QQuickView view->setSource(QUrl::fromLocalFile(“myqmlfile.qml”)) view->show()

4.QQmlContext

提供了对象实例化和表达式执行所需的上下文 所有对象都要在特定的上下文中实例化 QQmlContext在QML引擎中定义了一个上下文,允许将数据暴露给由QML引擎实例化的QML组件 QQmlContext属性能通过名字将数据显示绑定到上下文,使用setContextProperty() 例如: QQmlEngine engine; QStingListModel modelData; QQmlContext* context = engine.rootContext() context->setContextProperty(“stringModel”,&modelData) QQmlContext创建者需要有权去销毁QQmlContext对象 下方例子中context由根上下文中创建了一个新的上下文,modelData被添加到该新的的上下文, window销毁后,新创建的context必须显示销毁,可以将window作为context父对象,利用QT的对象内存结构自动销毁 例如: QQmlEngine engine; QStingListModel modelData; QQmlContext* context = new QQmlContext(engine.rootContext()) ; context->setContextProperty(“stringModel”,&modelData) //和下面代码的区别

QQmlComponent component(&engin); component.setData(“importQtQuick;ListView{model:stringModel}”,QUrl()); QObject* window=component.create();

在QQmlContext中设置一上下文(按照这样new QQmlContext(engine.rootContext())),上下文对象的是所有属性都可以在context中通过名称访问 使用上下文对象可以更简单快捷维护属性 例如: class MyDataSet:public QObject { Q_PROPERTY(QAbstractItemModel* myModel READ NOTIFY modelChanged) }; MyDataSet myDataSet; QQmlEngine engine; QQmlContext* context=new QQmlContext(engine.rootContext()); context->setContextObject(&myDataSet); //和上面代码的区别

QQmlComponent componet(&engine); componet.setData(“import QtQuick;ListView{model:myModel}”,QUrl()); component.create(context);

使用setContextProperty显示设置的属性优先于上下文对象的属性 QQmlEngine engine; QQmlContext* context1=new QQmlContext(engine.rootContext()); QQmlContext* context2=new QQmlContext(context1); //context2 是context1的子上下文。 context1->setContextProperty(“a”,12); context1->setContextProperty(“b”,15); context2->setContextProperty(“5”,15); //context2具有context1的全部属性

5.QQmlComponent

动态对象实例化, 可以使用C++直接创建,也可以通过createComponent在QML中创建 组件是可重用的、具有定义好的对外接口的封装QML类型, QQmlComponent封装了QML组件的定义,用于加载QML文档,需要QQmlComponent实例化QML的对象

例如: qml import QtQuick Item{width:100;height:100}

c++ #include #include #include int main(int argc,char* argv[]) { QCoreApplication a(argc,argv); QQmlEngine engine; QQmlComponent component(&engine,Qurl::fromLocalFile(“…/main.qml”)); QObject* myObj=component.create(); QuickItem* item = qobject_cast(myObj); qreal width = item->width(); return a.exec(); } 如果QQmlComponent要加载网络中的QML文件时,需要先获取到文件才能加载,所以有一个过程,会变成Loading,只有状态变为Ready后才能调用create void Init(){ QQmlComponent component(&engine,Qurl(“http://www.eample.com/main.qml”)); if(component->isLoading()) { QObject::connect(component,&QQmlComponent::statusChanged,this,&MyApplication::continuedLoading) } else { continuedLoading(); } }

void continuedLoading() { if(component->isError()) { qWarning<< component->errors(); }else { QObject* myObj = component->create(); } }

6.QQmlExpression

动态执行表达式 允许客户端在C++中利用一个特定的上下文执行javascript表达式,表达式的结果以QVariant返回 例子: xx.qml文件 Item{ width:100;height:100 } C++中 QQmlEngine engine = new QQmlEngine(); QQmlComponent component(engine,QUrl::fromLocalFile(“xx.qml”)); QObject* object=component.create(); QQmlExpression* express = new QQmlExpression(engine->rootContext(),object,“width*2”); int ret = expression->evaluate().toInt();

7.QML中注册C++类型

7.1 qmlRegisterType Qt5.14后不在推荐使用qmlRegisterType 7.2 基于宏的注册方式 Qt5.15后使用一组可以添加到类定义中的宏,注册C++,会将类型导出到QML中;

QML_ELEMENT: 最重要的宏 可以将所在的类提供给QML作为类型,类型名称就是类名 QML_NAMED_ELEMENT(name)可以自定义类型名

例子: c++文件 #include //必备 class Backend:public QObject { Q_OBJECT Q_PROPERTY(QString username READ userName WRITE setUserName NOTIFY usernameChanged)

QML_ELEMENT //必备

public: explicit Backend(QObject* parent = nullptr){} QString username(){return m_userName;} void setUserName(const QString &userName) { m_userName = userName; emit userNameChanged(); } signals: void userNameChanged(); private: QString m_userName; };

在pro文件中添加如下 CONFIG += qmltypes QML_IMPORT_NAME=io.qt.examples.backend QML_IMPORT_MAJOR_VERSION = 1 这样就可以在类型命名控件为《io.qt.examples.backend》中注册版本为1的类型 次要版本将从附加到属性、方法、信号的任何修订中派生,默认次要版本为0, 将QML_ADDED_IN_minor_VERSION()宏添加到类定义中,可以显示的将类型限制为特定的次要版中可用

在qml文件中 import QtQuick import QtQuick.Controls import io.qt.examples.backend //C++中的类型空间 ApplicationWindow{ id:root width:100;height:100 visible:true BackEnd{ id:backend onUserNameChanged:console.log(backend.userName); } Column{ spacing:10 anchors.centerIn:parent TextField{ placeholderText:qsTr(“User Name”) onTextChanged:backend.username = text } Label{ text:backend.username width:100;height:100 background:Rectangle{ color:“lightgrey” } } }

} 7.3 注册值类型 具有Q_GADGET宏的任何类型都可以注册为QML值类型 Q_GADGET是Q_OBJECT简化版,适用于不从QOBJECT派生,但希望使用QMetaObject的一些功能 可以使用Q_ENUM、Q_PROPERTY、Q_INVOKABLE;但不能使用信号和槽 值类型名称需要小写, 注册方式:QML_VALUE_TYPE或者QML_ANONYMOUS class Person{ Q_GADGET Q_PROPERTY(QString firstName READ firstName WRITE setFirstName NOTIFY fierstNameChanged) Q_PROPERTY(QString lastName READ lastName WRITE setLastName NOTIFY usernameChanged) QML_VALUE_TYPE(persion) //值类型名称需要小写, } 使用方式和7.2类似

7.4注册不可实例的对象类型 有时候需要将QObject派生类注册为不可实例化的对象类型 符合情况的C++类 - 该类是个接口类型,不应该被实例化 - 该类不需要向QML公开的基类 - 仅声明一些可以从QML访问的枚举 - 是应通过单例提供给QML的类型 QML提供了以下几种方法用于注册非实例化的类型的宏 QML_ANONYMOUS: 注册不可实例化,且无法从QML引用的C++类型 QML_INTERFACE:注册Qt接口类型 QML_UNCREATETABLE(reason):注册一个命名的C++类型,不可实例,但可被QML系统识别,需要搭配QML_ELEMENT或者QML_NAMED_ELEMENT QML_SINGLETON:注册一个可以从QML导入的单例类型;需要搭配QML_ELEMENT或者QML_NAMED_ELEMENT 单例允许QML使用命名空间访问其属性值、信号、函数,不需要手动实例化一个对象 单例类型不需要和QQmlContext关联,它被所有上下文共享 单例类型由QQmlEngine构造持有,engine销毁该单例销毁

8. 定义QML特定类型、属性

8.1 附加属性 QML中有一个附加属性、附加信号处理器,是附加到一个对象的额外特性 8.2属性修饰符类型 可以作用于QML对象实例的一种属性 属性值设置拦截器:在属性被设置时,用于过滤和改变设置值 属性值源:随时间推移,自动更新值

8.3指定QML对象为默认属性、父级属性 Q_CLASSINFO宏和DefaultProperty搭配指定默认属性 class A{ Q_CLASSINFO(“DefaultProperty”,“messages”) //将属性messages设置为默认属性 Q_CLASSINFO(“ParentProperty”,“boadr”) //告诉QML哪个属性表示QML层次结构父对象 } 8.4枚举类型 使用自定义枚举类型,需要先将类注册,枚举使用Q_ENUM()声明 class Message:public QObject { Q_OBJECT Q_PROPERTY(Status staus READ status NOTIFY statusChanged) public: enum Status{ready,Loading,Error}; Q_ENUM(Status) Status status( )const; signals: void statusChanged(); }

在qml文件中使用 Message { onStatusChanged: { if(status == Message.Ready) { console.log(“Message is loaded”) } } }

9.使用C++属性

QObject的子类或者包含有Q_GADGET宏的类的所有属性都能够被QML访问 可以使用Q_PROPERTY宏定义属性 例子 class Message:public QObject { Q_OBJECT Q_PROPERTY(Status staus READ status NOTIFY statusChanged) Q_PROPERTY(QString m_author READ author WRITE setAuthor NOTIFY authorChanged) public: enum Status{ready,Loading,Error}; Q_ENUM(Status) Status status( )const; QString authorconst{return m_author;} void SetAuthor(const QString& autho) { if(autho != m_author) { m_author=autho; emit authorChanged(); } } signals: void statusChanged(); void authorChanged(); private: QString m_author; } cpp文件中 QQuickView view; Message msg; view.engine()->rootContext()->setContextProperty(“msg”,&msg); view.setSource(QUrl::fromLocalFile(MyItem.qml)); view.show(); 在qml文件中: import QtQuick Text { width:100;height:100; text:msg.author //调用author() Component.onCompleted: { msg.author = “Jonah” //调用SetAuthor() } }

10.增强QML、C++交互性,属性都应该显示关联一个NOTIFY属性,属性改变时发射该信号

10.1 对象类型属性 如果类注册到QML,在qml中可以直接使用这个类 class Message : public QObject { Q_OBJECT Q_PROPERTY(QString m_author READ author WRITE setAuthor NOTIFY authorChanged) public: QString authorconst{return m_author;} void SetAuthor(const QString& autho) { if(autho != m_author) { m_author=autho; emit authorChanged(); } } signals: void authorChanged(); private: QString m_author; }

在qml中直接 Message{} 10.2对象列表属性 如果属性包含QObject子类列表,在QML中访问必须使用QQmlListProperty作为属性类型 class MessageBoadr: public QObject { Q_OBJECT Q_PROPERTY(QQmlListProperty messages READ messages) public: QQmlListProperty messages()const; //返回一个由QList m_messages构造的新的QQmlListProperty对象 { return QQmlListProperty(this,0,&MessageBoard::append_message); } private: static void append_message(QQmlListProperty* list,Message* msg) { MessageBoard* msgBoard=qobject_cast(list->object); if(msg) msgBoard->m_messages.append(msg); } QList m_messages; } 10.3属性组 属性组用于描述一个类型相关的特征 class MessageAuthor:publicQObject { Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(QString email READ email WRITE setEmail) } class Message:public QObject { Q_OBJECT Q_PROPERTY(MessageAuthor* author READ author) public: Message(QObject* parent):QObject(parent),m_author(new MessageAuthor(this)){} MessageAuthor* author()const{return m_author;} private: MessageAuthor* m_author; }

Message、MessageAuthor注册到QML后 Message { author.name:“aaa” author.email:“aaa@qq.com” } 10.4使用函数和槽、信号 QML中可以有条件的访问QObject子类的函数 使用Q_INVOKABLE标记的public函数 public的槽函数 class MessageBoard:public QObject { Q_OBJECT public: Q_INVOKABLE bool postMessage(const QString &msg) { return true; } signals: void newMessagePosted(const QString &subject); public slots: void refresh(){} }

cpp MessageBoard msgBoard QQuickView view; view.engine()->rootContext()->setContextProperty(“msgBoard”,&msgBoard); view->setSource(QUrl::fromLocateFile(“MyItem.qml”)); view.show();

qml import QtQuick Item { width:100;height:100; MouseArea { anchors.fill:parent onClicked: { var result = msgBoard.postMessage(“sss”); msgBoard.refresh(); } }

onNewMwssagePosted:(subject)=>{} } 10.5 C++中使用QML QML可以使用QQmlComponent、QQuickView进行加载; – QQmlComponent读取到qml后,将其转为c++对象,即可在C++中进行修改 – QQuickView也和QQmlComponent类似,不过由于QQuickView是QWindow的子类,所以被加载的对象还可以进行可视化渲染; 因此,QQuickView用于将一个可视化的QML与应用程序的图形界面整合 Item { width:100 height:100 } 使用QQmlComponent QQmlEngine engine; QQmlComponent component(&engine,QUrl::fromLocalFile(“main.qml”)); QObject* obj=component.create(); //… delete obj;

获取到QObject后,利用setPorperty、QQmlProperty对其属性修改 obj->setProperty(“width”,500); QQmlProperty(obj,“width”).write(600)

还可以转换成其他类型 QQuickItem* item=qobject_cast(object); item->setWidth(500); qDebug()setWidth(500); qDebug()

} } class MyClass:public QObject { Q_OBJECT public slots: void cppSlot(QString msg){} void cppSlot(QQuickItem* item){} }

main: QQuickView view(QUrl:;fromLocalFile(“MyItem.qml”)); QObject* item=view.rootObject(); MyClass myClass; QObject::connect(item,SIGNAL(qmlSignal(QString)),&myClass,SLOT(cppSlot(QSting))); QObject::connect(item,SIGNAL(qmlSignal(QVariant)),&myClass,SLOT(cppSlot(QVariant)));

view.show();

柚子快报邀请码778899分享:qt QML笔记八

http://yzkb.51969.com/

文章来源

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。