首页 > 编程知识 正文

qt单例模式,com组件服务

时间:2023-05-06 00:19:21 阅读:54910 作者:4368

个人资料

本文是《Qml组件化编程》系列文章中的第五篇,jsdxlb教授Qml和c的交互。

Qml已经有很多功能,但最终还是有不足和不适用的地方,需要通过与c的交互进行功能扩展。

这次,jsdxlb写出了所有Qml和c相互作用相关的知识点,尝试进行了彻底而全面的总结。

顺便说一下,jsdxlb的TaoQuick项目已经正式开源,包括动态改变皮肤、切换多语言等一系列文章的所有功能都集成到了TaoQuick中。

此外,jsdxlb在TaoQuick上使用连续集成(ci )技术,现在可以自动编译和发布Windows和Macos平台软件包,并提供千兆以太网的可释放性

互联网行业流行的DevOps理念在陶快速项目中获得了最佳实践。

(linux平台分发工具linuxdeployqt还存在一段时间的问题,但jsdxlb稍后会解决。)

地址在这里。 快去star吧。https://github.com/诚实百合/TaoQuick github.com

访问Qml

访问Qml有两种方法: findChild和QQmlComponent。

查找池

任何认识Qt的人都知道,Qt的很多对象都是QObject的子类,只要设置了parent,这些QObject就会成为父子关系,从而生成“对象树”。

如果存在根节点,则可以在findChild中检索树中的任何节点。

写一个简单的TaoObject,展示一下:

类taoobject

{

公共:

//传递构造函数、parent

是taoobject (taoobject * parent=nullptr ) : m _ p parent (parent ) )

{

if(m_pparent )是

{

m_pparent-appendchild(this;

}

}

//析构函数,析构函数children。 也就是说,子对象的自动回收机制。

~TaoObject () )

{

for(auto*pobj:m_Children ) )。

{

delete pObj;

}

m_children.clear (;

}

获取名称

常数qstring getname ()常数

{

return m_name;

}

//设定name

语音集名称(常量字符串名称)。

{

m_name=name;

}

查找//子对象

taoobject * find child (constqstringname ) )。

{

//首先检查自己的名字是否与目标的名字一致

if (m_name==name )

{

返回时间;

}

遍历//子对象进行查找

for(autopobj:m_Children ) ) ) ) ) ) ) ) ) ) )。

{

//递归调用,搜索深度优先

autoresobj=pobj-findchild(name );

是if(resobj )

{

返回修复;

}

}

返回空值;

}

保护性:

void appendchild (taoobject * child ) )。

{

m_children.push_back(child;

}

隐私:

//保存名称

QString m_name;

//子对象列表

std:vector m_children;

//父对象指针

TaoObject *m_pParent=nullptr;

(;

Qml的许多基本元素由QQuickItem继承,而QQuickItem由QObject继承。

因此,Qml中的许多对象都是QObject的子类,可以通过findChild方法获取对象指针。

得到QObject后,可以通过QObject_cast转换为具体类型使用,也可以直接使用QObject的invok方法。

例如,有以下Qml代码:

Item {

id:路由

.

应收账款

e {

id: centerRect

objectName: "centerRect" //必不可少的objectName

property bool canSee: visible //自定义属性,可以被C++ invok访问

signal sayHello() //自定义信号1,可以被C++ invok调用

signal sayHelloTo(name) //自定义信号2,带参数。可以被C++ invok调用。参数的名字要起好,后面通过这个名字来使用参数

function rotateToAngle(angle) //自定义js函数,旋转至指定角度。可以被C++ invok调用。

{

rotation = angle

return true;

}

}

...

}

那么在C++ 中访问的方式是:如果用QQuickView加载qml,就是

QQuickView view;

...

QObject *centerObj = view.rootObject()->findChild("centerRect");

if (!centerObj) { return;}如果用QQmlEngine加载qml,就是

QQmlEngine engine;

...

QObject *centerObj = engine.rootObject()->findChild("centerRect");

if (!centerObj) { return;}

(QObject类型也可以换成QQuickItem 或者其它)

拿到了对象指针,接下来就好办了

访问其属性

bool canSee = centerObj->property("canSee").toBool();

发射其信号(其实就是函数调用)

QMetaObject::invokeMethod(centerObj, "sayHello");

QMetaObject::invokeMethod(centerObj, "sayHelloTo", Q_ARG(QString, "Tao"))

调用其js函数,可以传参数过去,可以取得返回值

bool ok;

QMetaObject::invokeMethod(centerObj, "rotateToAngle", Q_RETURN_ARG(bool, ok), Q_ARG(qreal 180));

这里再补充一下, Qml中给自定义的信号写槽或连接到别的槽(Qml中的槽就是js函数):

Item {

id: root

...

Rectangle {

id: centerRect

objectName: "centerRect" //必不可少的objectName

signal sayHello() //自定义信号1

signal sayHelloTo(name) //自定义信号2,带参数。参数的名字要起好,后面通过这个名字来使用参数

function rotateToAngle(angle) //自定义js函数,旋转至指定角度

{

rotation = angle

}

onSayHello: { //信号1的槽

console.log("hello")

}

onSayHelloTo: { //信号2的槽,直接用信号定义时的参数名字name作为关键字访问参数

console.log("hello", name)

}

Component.onCompleted: {

//信号2 连接到 root的函数。参数会自动匹配。

sayHello.connect(root.rootSayHello)

}

}

...

function rootSayHello(name) {

console.log("root: hello", name)

}

}

QQmlComponent

C++中的QQmlComponent可以用来动态加载Qml文件,并可以创建多个实例,

对应Qml中的Component。Qml中还有一个Loader,也可以动态加载并创建单个实例。

(QQmlComponent这种方式不太多见,不过jsdxlb之前参与过开发一个框架,使用的就是QQmlComponent动态加载Qml,

完全在c++中控制界面的加载,加载效率、内存占用上都比纯Qml优秀。)

来看一个例子:

// Circle.qml

Rectangle {

width: 300

height: width

radius: width / 2

color: "red"

}

QQmlEngine engine;

QQmlComponent component(&engine, QUrl::fromLocalFile("Circle.qml"));

QObject *circleObject = component.create();

QQuickItem *item = qobject_cast(circleObject);

int width = item->width();

拿到对象指针,就和前面的一样了,这里不再赘述了。

Qml访问C++

Qml要访问C++的内容,需要先从C++把要访问的内容注册进Qml。

先说说能用哪些:

注册过后,Qml中可以访问的内容,包括 Q_INVOKABLE 修饰的函数、枚举、 QObject的属性 信号 槽

Q_INVOKABLE 函数可以用在普通的结构体或者类中,但是这种用法不常见/不方便。常见的是在QObject的子类中,给非槽函数设置为Q_INVOKABLE

枚举的注册Qt帮助文档很详细,而且5.10以后可以在qml中定义枚举了,这里jsdxlb就不展开了。

QObject的属性 信号 槽,都是可以通过注册后,在qml中使用的。信号、槽都可以带参数,槽可以有返回值。

class BrotherTao : public QObject

{

Q_OBJECT //这个宏一定要写上。不写可能的后果是,moc生成失败,信号 槽实现不了,编译过不了。

Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) //自定义属性,操作包括: 读、写和通知。Qml可以读写、获取通知

public:

...

//唱歌

Q_INVOKABLE void sing(); //invok函数,可以被Qml调用。可以带参数和返回值

public slots:

//打游戏,参数为次数,返回值为得分。

int playGame(int count); //槽函数,可以被Qml调用。可以带参数和返回值

signals:

//肚子饿了。参数为想吃的东西。

void hungry(const QString &foodName); //信号,可以被Qml接收。

...

};

这里要说的是,属性、函数参数、返回值的类型,都需要是Qml能识别的类型。

Qt的常用类型已经在Qt内部注册好了,自定义的需要单独注册。

再说说怎么用:

注册分为两种:注册类型和注册实例。

注册类并使用

//C++qmlRegisterType("BrotherTao",1, 0, "BrotherTao");

//qml

import BrotherTao 1.0

Item {

BrotherTao { //实例化一个对象

id: tao

onHungry: { //给信号写个槽函数

if (foodName === "蛋炒饭") { //示意一下,不要在意吃啥。

console.log("jsdxlb要吃蛋炒饭")

} else if (foodName === "水饺") {

console.log("jsdxlb要吃水饺")

}

}

}

...

Button {

onClicked: {

//这个按钮按下的时候,jsdxlb开始唱歌

tao.sing();

}

}

Button {

onClicked: {

//这个按钮按下的时候,jsdxlb开始打游戏

let score = tao.sing(3);

console.log("jsdxlb打游戏次数", 3, "得分为", score)

}

}

}

注册实例并使用

BrotherTao tao; //C++中创建的实例

//如果用QQuickView加载QmlQQuickView view;

...

view.rootContext()->setContextProperty("tao", &tao); //注意这个名字不要用大写字母开头,规则和Qml中的id不能用大写字母开头一样。

//如果用QQmlEngine加载QmlQQmlEngine engine;

...

engine..rootContext()->setContextProperty("tao", &tao); //注意这个名字不要用大写字母开头,规则和Qml中的id不能用大写字母开头一样。

/对象实例,qml不用再import了

Item {

Connections { //通过connectins连接信号

target: tao //指定target

onHungry: { //给信号写个槽函数

if (foodName === "蛋炒饭") { //示意一下,不要在意吃啥。

console.log("jsdxlb要吃蛋炒饭")

} else if (foodName === "水饺") {

console.log("jsdxlb要吃水饺")

}

}

}

...

Button {

onClicked: {

//这个按钮按下的时候,jsdxlb开始唱歌

tao.sing();

}

}

Button {

onClicked: {

//这个按钮按下的时候,jsdxlb开始打游戏

let score = tao.sing(3);

console.log("jsdxlb打游戏次数", 3, "得分为", score)

}

}

}

转载声明

联系方式

作者 jsdxlb

开发理念 弘扬鲁班文化,传承工匠精神

微信xsd2410421

QQ759378563

如果觉得jsdxlb写的还不错,还请为jsdxlb打个赏,您的赞赏是jsdxlb持续创作的源泉。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。