qt之qml与C++数据交互
qml与c++之间的交互天然的与flux架构一致。可以直接套用,所有的事件通过信号进行分发。与android的EventBus差不多。
qml传递数据给c++
一般用于传递qml【View】上面的一些操作。比方说点击事件,请求发起事件等等。
我使用的方式是,统一交给ActionCrateor.qml进行分发,这里涉及qml的单例方式,可以看这篇文章 要记得单例的使用要使用相对路径,比方说我本地的代码结构是
所以在别的目录里面使用就需要使用相对路径// /a/b/xxx.qml 相对于 /action/XActionCreator.qml的位置
import “…/…/action”
为了保持一致,我这边都是使用json进行传递,而不使用对象类型进行传递
//qmldir
singleton ActionCreator 1.0 XActionCreator.qml
singleton Constant 1.0 Constant.qml
// XActionCreator.qml pragma Singleton import QtQuick 2.0 import SigDispatcher 1.0 Item { //"send_xxx(作用)" 命名的规则 //发送事件 function send_initData(){ //统一发送 //调用某个对象的信号 dispatcher.sendEvent("active",""); } //切换专辑,重新请求 function send_getAlbumData(param){ //param 参数,请求参数,页数?cid? dispatcher.sendEvent("album_get_new",param); } //c++的对象 SigDispatcher{ id:dispatcher } }
此时需要在主入口处加上
SigDispatcher
qmlRegisterType <SigDispatcher> ("SigDispatcher", 1, 0, "SigDispatcher");
准备
//SigDispatcher.h #ifndef SIG_DISPATCHER_H #define SIG_DISPATCHER_H #include <QObject> #include <QString> #include <QHash> #include <QVector> #include <QVariant> #include "sig/signalreceiver.h" class SigDispatcher : public QObject { Q_OBJECT public: explicit SigDispatcher(QObject *parent = 0); //注册事件 static void addRegister(SignalReceiver * ); static void removeRegister(SignalReceiver *); static void removeAll(); signals: public slots: void sendEvent(QString cmd,const QVariant&); private: //命令,遍历获取是否支持该命令字 static QVector<SignalReceiver *> registers; //QHash<void*,QString> registers; }; #endif // SIG_DISPATCHER_H
//SigDispatcher.cpp #include "sigdispatcher.h" #include "txz_common.h" //SigDispatcher::registers = new QVector<SignalReceiver *>(); QVector<SignalReceiver *> SigDispatcher::registers; SigDispatcher::SigDispatcher(QObject *parent) : QObject(parent) { } void SigDispatcher::addRegister(SignalReceiver * regiseter) { registers.append(regiseter); } void SigDispatcher::removeRegister(SignalReceiver *regiseter) { registers.removeAll(regiseter); } void SigDispatcher::removeAll() { registers.clear(); } void SigDispatcher::sendEvent(QString cmd,const QVariant& data) { //auto_ptr<SigDispatcher> i(new SigDispatcher); for(SignalReceiver* iter:registers){ if(iter->needInvoke(cmd.toStdString())){ TXZ_LOGD("transform cmd: %s ,params: %s",cmd.toStdString().c_str(),data.toString().toStdString().c_str()); //需要处理这个事件 iter->invoke(cmd.toStdString(),(void*)(data.toString().toStdString().c_str())); } } }
//SignalReceiver.h #ifndef SIGNALRECEIVER_H #define SIGNALRECEIVER_H #include <string> #include <list> class SignalReceiver { public: SignalReceiver(){ } public: /** * @brief 是否需要拦截 * @param cmd * @return */ bool needInvoke(std::string cmd){ std::list<std::string>::iterator j; //遍历 for(j = cmds.begin();j!= cmds.end();j++){ if(*j == cmd){ return true; } } return false; } /** * @brief 处理, * @param cmd * @param data */ virtual void invoke(std::string cmd,void * data) =0; protected: std::list<std::string> cmds; }; #endif // SIGNALRECEIVER_H
c++接收数据
以上就可以将所有的qml传递的信息全部转换成c++可以识别的
void*
,如果你传递的是json则需要进行转换,如下(其中的json.h
是网上找的json的源码)【如果集成有问题,可以给我留言,我把我这边的json.h提供出来】//AlbumModel.cpp #include "json.h" void AlbumModel::invoke(std::string cmd, void *data) { TXZ_LOGD("cmd:%s",cmd.c_str()); if(cmd == strCmdAlbumMore){ }else if (cmd == strCmdAlbumNew){ //两次的cid不同才需要响应 TXZ_LOGD("data:%s",(char*)(data)); startRequestData(std::string((char*)(data))); } } void AlbumModel::startRequestData(std::string param) { //填写参数 Json::Value recvJson; Json::Reader().parse(param,recvJson, false); //str to json //Json::Reader().parse(str.toStdString().c_str(),str.toStdString().c_str()+str.toStdString().length(),recvJson, false); //char* to json //std::string stdStr = Json::FastWriter::writeFast(recvJson); //json to str //可以使用qml传递过来的值了。 TXZ_LOGD("json:%d",recvJson["cid"].asInt()); }
qml发送数据
qml怎么传递json过去呢?这里也是我踩得一个坑。
//a.qml import "../../action" Item{ property var currentCid: -1 //加载专辑数据 function loadAlbum(cid){ currentCid = cid; console.log("loadAlbum:",cid) //这里注意不用加双引号,js的语法,声明json的方式 var data = { cid:cid } //这里注意要使用JSON.stringify ActionCreator.send_getAlbumData(JSON.stringify(data)) } }
c++传递数据给到qml
传递给qml的类型必须是QXXX的,eg: QString,QJsonArray,QJsonObject 否则传递不到,这里注意一下
准备
需要传递数据则需要在qml中绑定c++的事件,如下
//main.cpp QQmlApplicationEngine engine; //将c++对象传递给qml进行使用 engine.rootContext()->setContextProperty("$resultActionType", &(ResultActionType::getInstance()));
//ResultActionType.h #ifndef RESULTACTIONTYPE_H #define RESULTACTIONTYPE_H #include <QObject> #include <QVariant> #include <QJsonArray> #include <QJsonObject> #include <QString> #include "base_type.h" class ResultActionType : public QObject { Q_OBJECT private: explicit ResultActionType(QObject *parent = 0); public: //单例 static ResultActionType& getInstance(); signals: //激活 void sig_active_success(); void sig_active_error(int); //分类 void sig_get_category_success(QJsonArray); void sig_get_category_error(int); //专辑 void sig_get_album_success(QJsonArray); void sig_get_album_error(int); //专辑详情 //音频 void sig_get_audio_success(QJsonArray); void sig_get_audio_error(int); //音频详情 void sig_get_audio_info_success(QJsonObject); void sig_get_audio_info_error(int); void sig_get_current_progress(QString,QString,QString,QString); void sig_get_current_status(int); void sig_get_notify_current_play_list(int ,QJsonArray); //搜索 public slots: }; #endif // RESULTACTIONTYPE_H
#include "resultactiontype.h" #include <QDebug> ResultActionType::ResultActionType(QObject *parent):QObject(parent) { } //这里要注意单例的写法: ResultActionType& ResultActionType::getInstance() { static ResultActionType resultActionType; return resultActionType; }
qml接收数据并展示
Item{ Component.onDestruction: { console.log("onDestruction") //解绑 $resultActionType.sig_get_audio_info_success.disconnect(showAudioInfo); $resultActionType.sig_get_album_error.disconnect(retryAudioInfo); $resultActionType.sig_get_current_progress.disconnect(showProgress); $resultActionType.sig_get_current_status.disconnect(showStatus); $resultActionType.sig_get_notify_current_play_list.disconnect(getPlayList); } Component.onCompleted: { playAudio(viewData[1]) //绑定监听 $resultActionType.sig_get_audio_info_success.connect(showAudioInfo); $resultActionType.sig_get_album_error.connect(retryAudioInfo); $resultActionType.sig_get_current_progress.connect(showProgress); $resultActionType.sig_get_current_status.connect(showStatus); $resultActionType.sig_get_notify_current_play_list.connect(getPlayList); // } ListView { id: listView width: parent.width/2-50 height: parent.height delegate: Item { x: 5 width: parent.width height: 40 Text { id: tvPlayListAudioName text: audioName } MouseArea{ anchors.fill: parent onClicked: { console.log("hello world",index); //点击播放 if(currentAudioId !== playList[index].audioId){ playAudio(playList[index].audioId); } } } } model: ListModel { id:playlistDataListModel } } //这里举一个例子,还有其他的类似showAudioInfo,retryAudioInfo,showProgress,showStatus function getPlayList(type,playlistData){ for (var i=0; i<playlistData.length; i++){ playlistDataListModel.append(playlistData[i]) } } }
note: 上面的getPlayList方法里面的playlistData是一个json所以传递个ListModel的时候需要有相应的key才能显示出来,比方说上面的例子中ListView中的delegate 里面的tvPlayListAudioName 需要名为audioName的key来显示数据,注意此时的playlistDataListModel如果指定了不同Key的ListElement会导致显示不出来。
C++发数据
#include <QJsonObject> #include "resultactiontype.h" // 显示音频播单 void _show_play_list_info() { int size = 10; //创建QJsonArray进行传递 QJsonArray jsonArray; for(int i = 0; i < size; i++) { QJsonObject object; object.insert("audioName","hello"); jsonArray.append(object); } emit ResultActionType::getInstance().sig_get_notify_current_play_list(type,jsonArray); }