在Qt界面开发时,用信号槽可以很容易实现各个窗口控件之间的交互,qml也是可以的,qml和C++可以相互调用,可以在qml代码中调用C++的类对象,也可以用C++类来获取qml的控件对象,下面分别介绍这两这种用法,需要源码的可以翻到最后直接下载。
一、qml调用C++ Qt 提供了两种在 QML 环境中使用 C++对象的方式∶
方式1:在C+中实现一个类,注册为 QML 环境的一个类型,在 QML 环境中使用该类型创建对象。
方式2:在 C++中构造一个对象,将这个对象设置为 QML 的上下文属性,在QML 环境中直接使用该属性。
不管哪种方式,对要导出的 C++类都有要求,不是一个类的所有方法、变量都可以在 QML 语境中使用,定义可以导出的 C++类 前提条件 要想将一个类或对象导出到 QML 中,下列的前提条件必须满足∶
(1)从 QObject 或 QObject 的派生类继承,并使用Q_OBJECT宏,这和使用信号与槽的前提条件一样的,这两个条件是为了让一个类能够进入Qt强大的元对象系统(meta-object system)中,只有使用元对象系统,一个类的某些方法或属性才可能通过字符串形式的名字来调用,才可以在 QML 中被访问。
(2)成员函数想在qml中被调用,则需要在声明前加上Q_INVOKABLE
(3)槽函数可以用类对象在qml代码中直接调用
(4)C++的成员属性可以用Q_PROPERTY宏设置
(5)枚举体需要用Q_ENUMS导出
下面介绍方式1, 例如下面这个类
#ifndef TESTBOX_H
#define TESTBOX_H
#include
class TestBox : public QObject
{
Q_OBJECT
Q_ENUMS(ColorType)
Q_PROPERTY(int mValue READ getValue WRITE setValue)
public:
explicit TestBox(QObject *parent = nullptr);
enum ColorType
{
Red,
Green,
Blue
};
// 成员函数想在qml中被调用,则需要在声明前加上Q_INVOKABLE
Q_INVOKABLE int fun1();
int getValue()
{
return m_value;
}
Q_INVOKABLE void setValue(int value)
{
m_value = value;
}
signals:
void sig_Value();
public slots:
void on_Get();
private:
int m_value = 0;
};
#endif // TESTBOX_H
类定义好后,在main.cpp中注册
#include
#include
#include "testbox.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType("cpp.qt.TestBox", 1, 0, "TestBox");
QQmlApplicationEngine engine;
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();
}
调用qmlRegisterType注册类TestBox,版本是1.0, 这个版本号可以自己定义。
最后在qml代码中调用
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import cpp.qt.TestBox 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
TestBox{
id:tb
mValue:123 //可以在这里给对象赋值
}
Button{
id:btn1
text:"getValue"
anchors.left: parent.left
anchors.leftMargin: 40
anchors.top: parent.top
anchors.topMargin: 60
onClicked: {
tb.on_Get() //调用槽函数
}
}
Button{
id:btn2
text:"setValue"
anchors.left: btn1.left
anchors.top: btn1.bottom
anchors.topMargin: 20
onClicked: {
tb.setValue(3456)
}
}
Button{
id:btn3
text:"getenum"
anchors.left: btn2.left
anchors.top: btn2.bottom
anchors.topMargin: 10
onClicked: {
valueTextFeild.text = TestBox.Blue //调用枚举
}
}
Button{
id:btn4
text:"invoke fun"
anchors.left: btn3.left
anchors.top: btn3.bottom
anchors.topMargin: 10
onClicked: {
valueTextFeild.text = tb.fun1() //调用普通成员函数
}
}
TextField
{
id:valueTextFeild
anchors.left: btn1.right
anchors.leftMargin: 15
anchors.top: btn1.top
}
//链接信号槽
Connections{
target: tb
onSig_Value:{
valueTextFeild.text = tb.mValue //获取成员属性值
}
}
}
运行界面如下:
方式2:
在main.cpp中直接创建C++类对象,例如下面的代码,
engine.rootContext()->setContextProperty("tb", new TestBox);
new对象 tb, 然后在qml中就可以直接使用tb了。
代码如下:
#include
#include
#include "testbox.h"
#include
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
//qmlRegisterType("cpp.qt.TestBox", 1, 0, "TestBox");
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("tb", new TestBox);
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();
}
这种方式有弊端,枚举值如法直接在qml中获得,可以用数字代替。
二、C++调用qml在C++代码中获取qml控件时,需要用到objectName
Text{
objectName: "textLabel"
text:"Hello World"
anchors.centerIn: parent
font.pixelSize: 26
}
Button{
objectName: "quitBtn"
anchors.right: parent.right
anchors.rightMargin: 10
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
text:qsTr("退出")
}
上面的控件在声明时,都设置了属性objectName, qt程序在初始化时有个对象树,在对象树中根据objectName调用findChild可以获取到控件对象指针
//C++获取qml的控件
QObject* pQuitBtn = pRoot->findChild("quitBtn");
if(pQuitBtn)
{
QObject::connect(pQuitBtn, SIGNAL(clicked()), &app, SLOT(quit()));
}
QObject *pText = pRoot->findChild("textLabel");
if(pText)
{
bool bRet = QMetaObject::invokeMethod(pText, "setText", Q_ARG(QString, "AAAA"));
qDebug()
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?