QT之QML从入门到精通(第七章)

QML与C++交互

使用全局对象

main.cpp

cpp 复制代码
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QScreen>
#include <QRect>
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    //全局对象,上下文对象
    QQmlContext* context = engine.rootContext();
    QScreen*screen =  QGuiApplication::primaryScreen();
    QRect rect = screen->availableGeometry();
    context->setProperty("SCREEN_WIDTH",rect.width()/2 ); // 定义一个全局的属性可以给qml去使用

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

main.qml

css 复制代码
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    visible: true
    width: SCREEN_WIDTH //从main.cpp中拿到这个变量的值
    height: screen.desktopAvailableHeight/2 //screen可以获取到屏幕的相关大小。
    title: qsTr("Hello World")


}

使用qmlRegisterType模板类

myobject.cpp

cpp 复制代码
#include "myobject.h"

MyObject::MyObject(QObject *parent) : QObject(parent)
{

}

MyObject *MyObject::getInst()
{
    static MyObject* obj = new MyObject;
    return obj;
}

int MyObject::iValue() const
{
    return m_iValue;
}

void MyObject::setIValue(int iValue)
{
    m_iValue = iValue;
}

QString MyObject::sString() const
{
    return m_sString;
}

void MyObject::setSString(const QString &sString)
{
    m_sString = sString;
}

myobject.h

cpp 复制代码
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <QObject>
#include <QtQml>

class MyObject : public QObject
{
    Q_OBJECT
//    QML_ELEMENT //声明为QML元素,低版本5.12 qt没有

public:
    explicit MyObject(QObject *parent = nullptr);
    static MyObject* getInst();
    void fun();

    int iValue() const;
    void setIValue(int iValue);

    Q_PROPERTY(int iValue MEMBER m_iValue NOTIFY iValueChanged) //这个和下面那个都可以,经测试,使用MEMBER可以触发信号,下面的不行。
//    Q_PROPERTY(int iValue READ iValue WRITE setIValue NOTIFY iValueChanged) //QT宏,iValue是声明的名称,可以通过名称获取,并且创建读取和设置的函数,在新加一个值改变的信号。
    Q_PROPERTY(QString qstr READ sString() WRITE setSString NOTIFY sStringChanged) //QT宏,iValue是声明的名称,可以通过名称获取,并且创建读取和设置的函数,在新加一个值改变的信号。


    QString sString() const;
    void setSString(const QString &sString);

private:
    int m_iValue; //光标定位在属性上,键盘按下Alt+Enter 选择第一个
    QString m_sString;

signals:
    void iValueChanged();
    void sStringChanged();
};

#endif // MYOBJECT_H

main.cpp

cpp 复制代码
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QScreen>
#include <QRect>
#include <QtDebug>
#include "myobject.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    //全局对象,上下文对象
    QQmlContext* context = engine.rootContext();
    QScreen*screen =  QGuiApplication::primaryScreen();
    QRect rect = screen->availableGeometry();
    qDebug()<<rect.width()/2;

    context->setProperty("SCREEN_WIDTH",500 ); // 定义一个全局的属性可以给qml去使用

//    context->setProperty("MyObject",MyObject::getInst()); //使用单例模式来创建一个对象。
    qmlRegisterType<MyObject>("MyObj",1,0,"MyObject"); //myobj qml要导入的名称,主版本,次版本,使用对象

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

main.qml

cpp 复制代码
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import MyObj 1.0

Window {
    visible: true
//    width: SCREEN_WIDTH //从main.cpp中拿到这个变量的值,12版本似乎拿不到。
    width: screen.desktopAvailableWidth/2
    height: screen.desktopAvailableHeight/2 //screen可以获取到屏幕的相关大小。
    title: qsTr("Hello World")
    property int  val: myobj.iValue

    MyObject{ //C++中的对象。
        id:myobj
        iValue: 1
        qstr: "12"
        Component.onCompleted: {
            console.log("ivalue = ",myobj.iValue," qstr = ",myobj.qstr)
        }
        onIValueChanged: { //这个信号来自与QT中的MODIFY信号,本人测试,在cpp中使用MEMBER方式可以绑定,其他不行
            console.log("iValue changed = ",iValue)
        }
    }
    Button{
        onClicked: {
            myobj.iValue =100
            console.log("clicked myobj.iValue = ",myobj.iValue)
        }
    }
    onValChanged: {
        console.log("val = ",val)
    }

}

QML端直接访问C++的函数

需要在C++类的函数使用Q_INVOKABLE宏,就可以完成直接访问,见下图。

C++端直接调用qml函数

QML发送信号C++接收

方式一:在QML端绑定信号

main.qml

css 复制代码
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import MyObj 1.0

Window {
    id:window
    visible: true
    width:600
    height: 400
    title: qsTr("QML与C++交互")
    signal qmlSig(int i,string s)

    MyObject{ //C++中的对象。
        id:myobj
        iValue: 1
        m_sString: "m_sString_test"
    }
    Button{
        onClicked: {
            console.log("click")
            qmlSig(10,"张三")  //点击发送信号,让C++端去接受他。
        }
    }
    //方式一:
    Connections{
        target: window
        onQmlSig:{
            myobj.cppSlot(i,s) //直接调用槽函数。
        }
    }
//    方式二
    Component.onCompleted: {
        qmlSig.connect(myobj.cppSlot)
    }
}

方式二:在C++端绑定信号

main.cpp

cpp 复制代码
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QScreen>
#include <QRect>
#include <QtDebug>
#include <QObject>

#include "myobject.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    qDebug()<<QGuiApplication::platformName();



    QQmlApplicationEngine engine;
    //全局对象,上下文对象
    QQmlContext* context = engine.rootContext();
    QScreen*screen =  QGuiApplication::primaryScreen();
    QRect rect = screen->availableGeometry();
    qDebug()<<rect.width()/2;

    context->setProperty("SCREEN_WIDTH",500 ); // 定义一个全局的属性可以给qml去使用

//    context->setProperty("MyObject",MyObject::getInst()); //使用单例模式来创建一个对象。
    qmlRegisterType<MyObject>("MyObj",1,0,"MyObject"); //myobj qml要导入的名称,主版本,次版本,使用对象

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    //engine加载完成之后
    auto list = engine.rootObjects(); //返回的是main.qml QML文件的所有对象。
     //第一个元素的windows
    QObject* window = list.first();
    QObject* btn = list.first()->findChild<QObject*>("mybtn");

    qDebug()<< window <<"|"<< window->objectName();
    qDebug()<< btn <<"|"<< btn->objectName();

    // 方式三
    QObject::connect(window,SIGNAL(qmlSig(int,QString) ),MyObject::getInst(),SLOT(cppSlot(int,QString))  );
//    MyObject* w = MyObject::getInst();
//    QObject::connect(window, &QQuickWindowQmlImpl_QML_0::qmlSig, //这里无法用qt5的信号槽连接。
//                      w,  &MyObject::cppSlot);

    return app.exec();
}

C++端发送信号绑定qml函数

方式一

main.cpp

cpp 复制代码
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QScreen>
#include <QRect>
#include <QtDebug>
#include <QObject>

#include "myobject.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    qDebug()<<QGuiApplication::platformName();



    QQmlApplicationEngine engine;
    //全局对象,上下文对象
    QQmlContext* context = engine.rootContext();
    QScreen*screen =  QGuiApplication::primaryScreen();
    QRect rect = screen->availableGeometry();
    qDebug()<<rect.width()/2;

    context->setProperty("SCREEN_WIDTH",500 ); // 定义一个全局的属性可以给qml去使用

//    context->setProperty("MyObject",MyObject::getInst()); //使用单例模式来创建一个对象。
    qmlRegisterType<MyObject>("MyObj",1,0,"MyObject"); //myobj qml要导入的名称,主版本,次版本,使用对象

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    //engine加载完成之后
    auto list = engine.rootObjects(); //返回的是main.qml QML文件的所有对象。
     //第一个元素的windows
    QObject* window = list.first();
    QObject* btn = list.first()->findChild<QObject*>("mybtn");

    qDebug()<< window <<"|"<< window->objectName();
    qDebug()<< btn <<"|"<< btn->objectName();

    // 方式三
    QObject::connect(window,SIGNAL(qmlSig(int,QString) ),MyObject::getInst(),SLOT(cppSlot(int,QString))  );
//    MyObject* w = MyObject::getInst();
//    QObject::connect(window, &QQuickWindowQmlImpl_QML_0::qmlSig, //这里无法用qt5的信号槽连接。
//                      w,  &MyObject::cppSlot);

    return app.exec();
}

main.qml

cpp 复制代码
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import MyObj 1.0

Window {
    id:window
    visible: true
    width:600
    height: 400
    objectName: "mywindow"
    title: qsTr("QML与C++交互")
    signal qmlSig(int i,string s)

    MyObject{ //C++中的对象。
        id:myobj
        iValue: 1
        m_sString: "m_sString_test"
    }
    Button{
        objectName: "mybtn"
        onClicked: {
            console.log("click")
//            myobj.cppSig(100,"test");
            myobj.fun()
        }
    }
    Connections{
        target: myobj
        onCppSig:{
            console.log(i,s);
        }
//        function onCppSig(i,s){
//            qmlSlot(i,s)
//        }
    }

}

myobject.cpp

cpp 复制代码
#include "myobject.h"

MyObject::MyObject(QObject *parent) : QObject(parent)
{

}

MyObject *MyObject::getInst()
{
    static MyObject* obj = new MyObject;
    return obj;
}

void MyObject::fun()
{
    qDebug()<<__FUNCTION__;
    emit cppSig(1,"C++");
}

int MyObject::iValue() const
{
    return m_iValue;
}

void MyObject::setIValue(int iValue)
{
    m_iValue = iValue;
}

QString MyObject::sString() const
{
    return m_sString;
}

void MyObject::setSString(const QString &sString)
{
    m_sString = sString;
}

void MyObject::cppSlot(int i, QString s)
{
    qDebug()<<__FUNCTION__ <<i<< s;
}

myobject.h

cpp 复制代码
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <QObject>
#include <QtQml>

class MyObject : public QObject
{
    Q_OBJECT
//    QML_ELEMENT //声明为QML元素,低版本5.12 qt没有

public:
    explicit MyObject(QObject *parent = nullptr);
    static MyObject* getInst();
    Q_INVOKABLE void fun(); //Q_INVOKABLE宏可以让qml直接访问函数。

    int iValue() const;
    void setIValue(int iValue);

    Q_PROPERTY(int iValue MEMBER m_iValue NOTIFY iValueChanged) //这个和下面那个都可以,经测试,使用MEMBER可以触发信号,下面的不行。
    Q_PROPERTY(QString m_sString MEMBER m_sString NOTIFY sStringChanged) //QT宏,iValue是声明的名称,可以通过名称获取,并且创建读取和设置的函数,在新加一个值改变的信号。

    QString sString() const;
    void setSString(const QString &sString);

private:
    int m_iValue; //光标定位在属性上,键盘按下Alt+Enter 选择第一个
    QString m_sString;
public slots:
    void cppSlot(int i,QString s);
signals:
    void iValueChanged();
    void sStringChanged();

    void cppSig(int i,QString s);
};

#endif // MYOBJECT_H

方式二

main.cpp

cpp 复制代码
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QScreen>
#include <QRect>
#include <QtDebug>
#include <QObject>

#include "myobject.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    qDebug()<<QGuiApplication::platformName();



    QQmlApplicationEngine engine;

    qmlRegisterType<MyObject>("MyObj",1,0,"MyObject"); //通过模板创建
    //通过单例创建
//    qmlRegisterSingletoInstance("MyObj",1,0,"MyObject",MyObject::getInst() );//没有这个方法qt15引入。

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    //engine加载完成之后
    auto list = engine.rootObjects(); //返回的是main.qml QML文件的所有对象。
     //第一个元素的windows
    QObject* window = list.first();
    QObject* btn = list.first()->findChild<QObject*>("mybtn");

    qDebug()<< window <<"|"<< window->objectName();
    qDebug()<< btn <<"|"<< btn->objectName();

    // 方式三
    QObject::connect(window,SIGNAL(qmlSig(int,QString) ),MyObject::getInst(),SLOT(cppSlot(int,QString))  );

    QObject::connect(MyObject::getInst(),SIGNAL(cppSig(QVariant,QVariant) ),window,SLOT(qmlSlot(QVariant,QVariant) )  );

    return app.exec();
}

main.qml

css 复制代码
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import MyObj 1.0

Window {
    id:window
    visible: true
    width:600
    height: 400
    objectName: "mywindow"
    title: qsTr("QML与C++交互")
    signal qmlSig(int i,string s)

    MyObject{ //C++中的对象。
        id:myobj
        iValue: 1
        m_sString: "m_sString_test"
    }

    Button{
        objectName: "mybtn"
        onClicked: {
            console.log("click")
            myobj.fun()  //MyObject.fun()
        }
    }
    function qmlSlot(i,s){ // 参数类型 对应cpp端 都是QVariant
        console.log(i,s);
    }

    Connections{
        target: myobj
        onCppSig:{
            console.log(i,s);
        }
//        function onCppSig(i,s){
//            qmlSlot(i,s)
//        }
    }

}
相关推荐
SEO-狼术24 分钟前
Enhance Security in Software Crack
数据库
坊钰27 分钟前
【Java 数据结构】移除链表元素
java·开发语言·数据结构·学习·链表
chenziang132 分钟前
leetcode hot100 LRU缓存
java·开发语言
计算机毕设定制辅导-无忧学长35 分钟前
Redis 初相识:开启缓存世界大门
数据库·redis·缓存
会说法语的猪38 分钟前
springboot实现图片上传、下载功能
java·spring boot·后端
码农老起38 分钟前
IntelliJ IDEA 基本使用教程及Spring Boot项目搭建实战
java·ide·intellij-idea
m0_7482398343 分钟前
基于web的音乐网站(Java+SpringBoot+Mysql)
java·前端·spring boot
时雨h1 小时前
RuoYi-ue前端分离版部署流程
java·开发语言·前端
麒麟而非淇淋1 小时前
Day13 苍穹外卖项目 工作台功能实现、Apache POI、导出数据到Excel表格
java