一、全局属性
在main.cpp中通过 QQmlApplicationEngine engine 获得全局对象
QQmlApplicationEngine engine;
//全局对象 上下文对象
QQmlContext* context = engine.rootContext();
//获取屏幕的大小
Screen *screen= QGuiApplication::primaryScreen();
QRect rect= screen->virtualGeometry(); //整个屏幕的大小
//注册的上下文对象 它是作用于全局 有重命名的风险
context->setContextProperty("SCREEN_WIDTH",rect.width()/2); //设置全局属性 所有QMl文件都能访问得到的
在qml中使用 SCREEN_WIDTH 全局属性
width: SCREEN_WIDTH //screen.desktopAvailableWidth 获取整个屏幕的宽度
二,创建自定义对象,在QMl中使用
1.创建一个MyObject类
2.在myobject.h中定义一些属性,以便在qml中可以使用 并为每个属性添加读写的方法和相应的信号
class MyObject : public QObject
{ Q_OBJECT
public:
explicit MyObject(QObject *parent = nullptr);
int iValue() const;
void setIValue(int iValue);
QString sString() const;
void setSString(const QString &sString);
//定义一个函数 加Q_INVOKABLE 就可以让qml访问
Q_INVOKABLE void func();
private:
//生成get 和set 方法
int m_iValue;
QString m_sString;
//宏
//第一种方式
//声明一个名称 int iValue 想是QMl 中width
//READ iValue --->通过那个函数读的
// WRITE setIValue---》通过那个函数写的
//NOTIFY iValueChanged 当前这个值修改会发出iValueChanged信号
/* Q_PROPERTY(int iValue READ iValue WRITE setIValue NOTIFY iValueChanged) Q_PROPERTY(QString sString READ sString WRITE setSString NOTIFY sStringChanged)*/ //第二种方式
Q_PROPERTY(int iValue MEMBER m_iValue NOTIFY iValueChanged)
Q_PROPERTY(QString sString MEMBER m_sString NOTIFY sStringChanged)
public slots:
//槽函数
void ccpSlot(int i,QString str);
signals:
void iValueChanged();
void sStringChanged();
//定义一个信号,在qml中绑定槽函数
void cppSig(QVariant i,QVariant s);
};
2.在myobject.cpp中实现
#include "myobject.h"
MyObject::MyObject(QObject *parent) : QObject(parent) {
}
MyObject *MyObject::getInstance() { static MyObject * obj = new MyObject(); return obj; }
int MyObject::iValue() const { return m_iValue; }
void MyObject::setIValue(int iValue) { if(m_iValue == iValue) return;
m_iValue = iValue; //发出信号 emit iValueChanged(); }
QString MyObject::sString() const { return m_sString; }
void MyObject::setSString(const QString &sString) { if(m_sString == sString) return; m_sString = sString; emit sStringChanged(); }
void MyObject::func() { emit cppSig(101,"王五"); //发送信号 qDebug()<<__FUNCTION__;//当前函数名称
}
void MyObject::ccpSlot(int i, QString str) { qDebug()<<__FUNCTION__<<" "<
3.在main.cpp中访问 定义这个复杂的类型
有两种方式
#include
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine; // //全局对象 上下文对象 QQmlContext* context = engine.rootContext();
//获取屏幕的大小 QScreen *screen= QGuiApplication::primaryScreen(); QRect rect= screen->virtualGeometry(); //整个屏幕的大小 //注册的上下文对象 它是作用于全局 有重命名的风险 context->setContextProperty("SCREEN_WIDTH",rect.width()/2); //设置全局属性 所有QMl文件都能访问得到的 //qml中就可以访问这个对象myObjectOO //但是qml 并不能认识这个这个复杂的类型
//方式一 //context->setContextProperty("myObjectOO",MyObject::getInstance());//一般不用这个方法
//方式二 //四个参数 //第一个参数是qml中导入的名称 import HelloMyObj 1.0 //第二个第三个参数分别是主次版本号;第四个指的是QML中类的名字。 //qmlRegisterType
//创建一个全局的单例的模式 qmlRegisterSingletonInstance("HelloMyObj",1,0,"MyObject",MyObject::getInstance());
/// //地址 const QUrl url(QStringLiteral("qrc:/CPPSlotSignal.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);
/ //C++端绑定qml中发出的信号 //engine 加载完成后 load以后 auto list = engine.rootObjects(); //返回CPPSlotSignal.qml 中所有的对象 //auto objectName = list.first()->objectName(); // auto btnName = list.first()->findChild /// return app.exec(); } 4.在qml中访问 需要导入对象名和主次版本号 ,才能正式使用 import HelloMyObj 1.0 import QtQuick 2.14 import QtQuick.Window 2.14 import QtQuick.Controls 2.12 import HelloMyObj 1.0 Window { id: window property int value: myobj.ivalue visible: true width: 640 height: 480 title: qsTr("hello") MyObject{ id: myobj iValue:20 sString:"hello" } onValueChanged: { console.log(value) } Button{ onClicked: { myobj.iValue = 20 } } 三、QML端发送信号,绑定c++端的函数 1.在qml写好信号,并发出 Window { id: window objectName: "window" visible: true width: 640 height: 480 title: qsTr("QML端发送信号,绑定c++端的函数") //信号 signal qmlSig(int i,string s) Button { objectName: "btnClick" onClicked: { //发送信号 qmlSig(22,"hello") } } 2.在类中定义槽函数 public slots: //槽函数 void ccpSlot(int i,QString str); 实现 void MyObject::ccpSlot(int i, QString str) { qDebug()<<__FUNCTION__<<" "< } 3.绑定信号与槽函数 3.1在main.cpp绑定----C++端绑定qml中发出的信号 //engine 加载完成后 load以后 auto list = engine.rootObjects(); //返回CPPSlotSignal.qml 中所有的对象 //auto objectName = list.first()->objectName(); // auto btnName = list.first()->findChild // qDebug()< auto window = list.first(); //绑定 QObject::connect(window,SIGNAL(qmlSig(int,QString)), MyObject::getInstance(),SLOT(ccpSlot(int,QString))); 3.2在qml端绑定C++类的槽函数 两种方式 MyObject{ id: myobj } //连接C++中槽函数 //1. /*Connections{ target: window //发出者 function onQmlSig(i,str){ myobj.ccpSlot(i,str) } } */ //2.在组件完成时与连接 /* Component.onCompleted: { qmlSig.connect(myobj.ccpSlot) } */ 四、c++端发出信号,qml端绑定槽函数 1.myobject.h的定义信号 //定义一个信号,在qml中绑定槽函数 void cppSig(QVariant i,QVariant s); 2.在qml中定义槽函数 function qmlSlot(i,s){ // 参数类型 对应CPP端 都是QVariant console.log("qml",i,s) } 3.绑定 3.1c++端绑定 auto list = engine.rootObjects(); auto window = list.first(); QObject::connect(MyObject::getInstance(),SIGNAL(cppSig(QVariant,QVariant)), window,SLOT(qmlSlot(QVariant,QVariant))); 3.2qml端绑定 Connections{ target: MyObject //发出者 function onCppSig(i,str){ qmlSlot(i,str) } 4.可以不用在qml实现MyObject 对象,只需要在main中创建一个全局的单例的模式 qmlRegisterSingletonInstance("HelloMyObj",1,0,"MyObject",MyObject::getInstance()); 五、C++端直接调用QML函数 1.qml中写函数 function qmlFunc(i,s){ return " are you ok?" } 2.在main.cpp中调用 auto list = engine.rootObjects(); //返回CPPSlotSignal.qml 中所有的对象 auto window = list.first(); //调用QML端的函数 //第一参数,拥有者 第二参数 函数名称 第三参数 保存到哪 后面就是要传递的参数 QVariant resFunc; QVariant arg_1 = 123; QVariant arg_2 = "I am fine "; QMetaObject::invokeMethod(window,"qmlFunc", Q_RETURN_ARG(QVariant,resFunc), Q_ARG(QVariant,arg_1), Q_ARG(QVariant,arg_2)); qDebug()<<"res = "< 3.在qml中调用c++中的函数 3.1在myobject.h中定义 //定义一个函数 加Q_INVOKABLE 就可以让qml访问 Q_INVOKABLE void func(); 3.2在qml中使用 Button { objectName: "btnClick" onClicked: { MyObject.func() } } 相关链接
发表评论