当前位置: 代码迷 >> 综合 >> 【QML】QML和C++在QMainWindow框架下接口(亲测原创非抄袭)
  详细解决方案

【QML】QML和C++在QMainWindow框架下接口(亲测原创非抄袭)

热度:49   发布时间:2023-10-21 01:41:03.0

也不知道是QML用的人少,还是抄博客成风,网上关于QML和C++交互的文章几乎千篇一律,而且基本都是不能用了。

比如这篇文章:Qt:QML:QML于C++交互之信号与槽(signal&slot )_云淡风轻-CSDN博客_qml接收c++信号

连接 qml中函数与c++中信号:

Connections{//qml 连接 c++ 信号target:interactiononConnectcppsignal:{label2.text=strMsg;}}

这种方法是真的厉害,也不知道博主抄的时候有没有自己试过,反正我是一直报错,找不到onConnectcppsignal。

(一)在QMainWindow框架下,C++调用QML显示界面

1-我是通过创建一个 QQuickWidget *m_quickWidget 实现的:

    QQuickWidget *m_quickWidget=new QQuickWidget();QUrl source("qrc:/Screen_QML_Main.qml");m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView );m_quickWidget->setSource(source);

2-另外还有一种方式是QQmlComponent+QQmlEngine

QQmlEngine engine;
QQmlComponent component(&engine, "MyItem.qml");
QObject *object = component.create();

但第二种方法是单独把QML显示出来,目前还未试过,应该是出现QMainWindow和QML两个窗口。

(二)通过互相调用函数作为接口

1-在QML中用QML/JS调用C++

(1.1)声明的时候前面加上:Q_INVOKABLE

Q_INVOKABLE int qml_getRecordVal_toint16(int i_dec);

或者直接声明为

public slots:

因为slots和signals是经过QT特殊处理的,QML可以直接调用,否则普通函数都是向QML屏蔽的。

(1.2)然后绑定到QML

在qmainwindows的构造函数里:

 m_quickWidget->rootContext()->setContextProperty("$sql_mcDefine", sql_mcDefine);

上述语句是把另一个类对象绑定进去(1.1)里面声明就是在 Sql_MCDefine 这个类里面声明的。如果你想在qmainwindows里面声明,就把qmainwindows传进去

 m_quickWidget->rootContext()->setContextProperty("$qmainwindows", this);

 (1.3)在QML里面用双引号里面的关键字调用

$sql_mcRecorder.qml_getRecordVal_toint16(2);

其实绑定之后相当于 Screen_QML_Main.qml 根目录下多了一个 sql_mcDefine 的 property。

 

2-在qmainwindows中用C++调用QML/JS

(2.1)使用 QMetaObject

    QMetaObject::invokeMethod((QObject *)m_quickWidget->rootObject(),"recall");

其中recall就是QML里面自定义的一个自定义的JS函数。

m_quickWidget->rootObject()返回一个QQuickItem,就是指向了 Screen_QML_Main.qml 根目录。不过不能直接用,要强制转化为(QObject *)。 千万要跟 rootContext 区分,rootContext 返回的不是指向 Screen_QML_Main.qml 根目录,找不到 recall函数。

 

(三)使用信号互相连接

1-QML穿信号到C++

参考:Interacting with QML Objects from C++ | Qt QML 5.15.6

(1.1)在QML定义信号

// MyItem.qml
import QtQuick 2.0Item {id: itemwidth: 100; height: 100signal qmlSignal(anObject: Item)MouseArea {anchors.fill: parentonClicked: item.qmlSignal(item)}
}

(1.2)在C++进行connect

class MyClass : public QObject
{Q_OBJECT
public slots:void cppSlot(QQuickItem *item) {qDebug() << "Called the C++ slot with item:" << item;qDebug() << "Item dimensions:" << item->width()<< item->height();}
};int main(int argc, char *argv[]) {QGuiApplication app(argc, argv);QQuickView view(QUrl::fromLocalFile("MyItem.qml"));QObject *item = view.rootObject();MyClass myClass;QObject::connect(item, SIGNAL(qmlSignal(QVariant)),&myClass, SLOT(cppSlot(QVariant)));view.show();return app.exec();
}

 

2-QML发,C++收

这个可以说是找遍全网没找到,找到的都是抄来抄去的错方法。

(2.1)在已经和QML绑定的C++类(绑定就是(二)(1.2)所述)里面声明一个信号

signals:void sn_sqlWriteFinish();

就是普通的qt信号,平平无奇

(2.2)依然是在C++中进行connect

m_quickWidget->rootContext()->connect(sql_mcRecorder, SIGNAL(sn_sqlWriteFinish()), (QObject *)m_quickWidget->rootObject(), SLOT(recall()));

其中一些重要的地方见(二)(2.1),QML的槽函数就是普通的JS函数,根本不需要额外声明。