【零基础学QT】【048】Qml与C++互相调用

为了节省代码,把精力放在技术本身上,我们直接复用上篇博客中的main.qml来演示

Qml代码


	//main.qml
	
	import QtQuick 2.13
	import QtQuick.Window 2.13
	
	//窗口节点
	Window {
	    id: root
	    visible: true
	    width: 640
	    height: 480
	    title: "Qt Quick Demo"
	
	    IconButton {
	        anchors.fill: parent
	        anchors.margins: 100
	
	        icon: "images/1.png"
	        text: "Print Mouse Position"
	    }
	}


	//IconButton.qml

	IconButtonForm {
	    id: _root
	    width: 640
	    height: 480
	
	    //点击信号
	    signal clicked(var mouse)
	
	    //点击事件
	    clickRect.onClicked: {
	        _root.clicked(mouse)
	    }
	    
	    //监听属性变化
	    onWidthChanged: {
	        console.debug("IconButton width change")
	    }

	    //Qml方法
	    function sum(a, b) {
	        return a + b
	    }
	}
	

C++将Qml加载为对象
C++可以通过QQmlComponent和QQuickView两种方式来获得Qml中的对象


	//QQmlComponent

	int main(int argc, char *argv[]) {
	    QGuiApplication app(argc, argv);
	
	    QQmlApplicationEngine engine;
	    QQmlComponent component(&engine, "qrc:///main.qml");  //注意路径写法
	    QObject *object = component.create();
	    qdebug << object->metaObject()->className();  //打印结果为:QQuickWindowQmlImpl
	    QQuickWindow *window = qobject_cast<QQuickWindow *>(object);
	    qdebug << window->width();
	
	    return app.exec();
	}


	//QQuickView

	int main(int argc, char *argv[]) {
	    QGuiApplication app(argc, argv);
	
	    QQuickView view;  //QQuickView不支持用Window作为根节点
	    view.setSource(QUrl("qrc:///IconButton.qml"));  //注意路径写法
	    view.show();
	    QObject *object = view.rootObject();
	    qdebug << object->metaObject()->className();  //打印结果为:IconButton_QMLTYPE_1
	    QQuickItem *item = qobject_cast<QQuickItem *>(object);
	    qdebug << item->width();
	
	    return app.exec();
	}

C++控制Qml对象属性
C++控制Qml对象属性有两种方式,一种是get/set,一种是read/write
这两种方式的区别在于,后者会移除属性之前已有的约束
比如我们设置了【width:height】,在调用了QQmlProperty::write()之后,这个约束便会解除
C++从Qml中读取的对象属性,全部通过QVariant进行封装
当通过C++改变Qml中的对象属性时,会触发Qml中的属性监听器,比如width改变时,onWidthChanged也会执行


	int main(int argc, char *argv[]) {
	    QGuiApplication app(argc, argv);
	
	    QQuickView view;
	    view.setSource(QUrl("qrc:///IconButton.qml"));
	    view.show();
	    QObject *object = view.rootObject();
	
	    object->property("width");
	    object->setProperty("width", 1000);
	
	    QQmlProperty(object, "width").read();
	    QQmlProperty(object, "width").write(1000);
	
	    return app.exec();
	}

C++调用Qml对象方法


    QQuickView view;
    view.setSource(QUrl("qrc:///IconButton.qml"));
    view.show();
    QObject *object = view.rootObject();

    QVariant returnValue;
    QMetaObject::invokeMethod(object, "sum", Q_RETURN_ARG(QVariant, returnValue), Q_ARG(QVariant, 1), Q_ARG(QVariant, 2));
    qdebug << returnValue;

C++槽函数响应Qml信号
C++中的槽函数和Qml中的信号,按照正常的connect方式连接即可,因为connect方法里面的参数本质上只是字符串,剩下工作都由Qt编译器来自动完成,既然我们已经知道信号和槽的名字,直接写进入即可
为了定义一个C++槽函数,我们需要增加一个QObject类,由于Qt要求必须将Q_OBJECT宏写在头文件中,我们将main.cpp改成main.h,这样就可以保证所有代码在同一个文件中,虽然不太规范,但方便讲解


	//main.h
	
	class QmlClass : public QObject {
	    Q_OBJECT
	
	  public slots:
	    void onMouseClick(QVariant mouse) {
	        QObject *pEvent = mouse.value<QObject *>();
	        qdebug << pEvent->property("button");
	        qdebug << pEvent->property("y");
	        qdebug << pEvent->property("y");
	    }
	};
	
	int main(int argc, char *argv[]) {
	    QGuiApplication app(argc, argv);
	
	    QQuickView view;
	    view.setSource(QUrl("qrc:///IconButton.qml"));
	    view.show();
	    QObject *qmlObject = view.rootObject();
	
	    QmlClass qmlClass;
	    QObject::connect(qmlObject, SIGNAL(clicked(QVariant)), &qmlClass, SLOT(onMouseClick(QVariant)));
	
	    return app.exec();
	}


Qml使用C++中的类


	//main.h

	#include <qlib.h>
	#include <QGuiApplication>
	#include <QQmlApplicationEngine>
	#include <QQuickView>
	
	class CppClass : public QObject {
	    Q_OBJECT
	
	    //定义一个属性,可以在Qml中访问这个属性
	    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
	
	  public:
	    QString name() {
	        return mName;
	    }
	
	    //名字改变时,发出信号,可以在Qml中响应这个信号
	    void setName(QString &name) {
	        if (name == mName) return;
	        QString temp = mName;
	        mName = name;
	        emit nameChanged(temp, name);
	    }
	
	    //定义一个方法,可以在Qml中访问这个方法
	    Q_INVOKABLE void printName() {
	        qdebug << name();
	    }
	
	  signals:
	    //定义名字改变的信号,Qml中会自动生成名为onNameChanged的信号处理器
	    void nameChanged(QString oldName, QString newName);
	
	  private:
	    QString mName;
	};
	
	int main(int argc, char *argv[]) {
	    QGuiApplication app(argc, argv);
	
		//注册在Qml中的模块名和类名
	    qmlRegisterType<CppClass>("cpp", 1, 0, "CppClass");
	
	    QQuickView view;
	    view.setSource(QUrl("qrc:///IconButton.qml"));
	    view.show();
	
	    return app.exec();
	}



	//IconButton.qml

	import QtQuick 2.13
	import cpp 1.0
	
	IconButtonForm {
	    id: _root
	    width: 640
	    height: 480
	
	    //使用C++中的类
	    CppClass {
	        id: cppClass
	        name: "hello" //使用C++中的属性
	
	        //响应C++中的信号
	        onNameChanged: {
	            console.debug("onNameChanged:", oldName, newName)
	            printName() //调用C++中的方法
	        }
	    }
	
	    //点击时改变cppClass的名称
	    clickRect.onClicked: {
	        cppClass.name = Math.random()
	    }
	}

发布了442 篇原创文章 · 获赞 45 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/u013718730/article/details/104174404