也不知道是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函数,根本不需要额外声明。