找回密码
 立即注册
Qt开源社区 门户 查看内容

qt之qml与C++数据交互

2019-3-16 23:28| 发布者: admin| 查看: 2026| 评论: 0

摘要: 我是一名Android开发出生,在大学学的是javaweb方向的开发,不能说javaweb方向的东西都精通,但是至少应该能捡的起来。因为个人的爱好“喜欢看到一些看起来炫酷的东西”所以开始了漫长的接近四年的开发之旅。也是因 ...

我是一名Android开发出生,在大学学的是javaweb方向的开发,不能说javaweb方向的东西都精通,但是至少应该能捡的起来。因为个人的爱好“喜欢看到一些看起来炫酷的东西”所以开始了漫长的接近四年的开发之旅。也是因为工作的原因,开始接触linux的应用层开发。

学习的心得:从android学习的过程中,我明白了一件事,懂得站在巨人的肩膀上。在查询资料的过程中也发现,纵然qml的起源比android要早的多,但是网上关于qml的学习资料却没有android的多。作为一名android过来的,我开始分享工作中接触到的东西,希望对更多人有所帮助,试一次总结,也是一次分享。

记得有个门外汉,曾经问过我一个问题:“如果有个代码仓库,是不是所有的程序员都是从里面根据自己的需要复制黏贴就可以了?” 。我的回答是肯定的,只是目前对于代码仓库的筛选与查找是我们的工作。

在我做Android的时候我发现,很多原来可以从github上面找到的功能自己写了还有一堆的bug,而且非常痛苦,所以真的建议大家在写具体的功能之前,先去github上面找找,也许能帮助你。github上面可以过滤语言,大家可以过滤一下qml进行查看,目前基本上都是一些example。不过也非常的有帮助。

在我做公司安排的项目的时候,本着沿用android上面可以复用的知识点的原则,架构方面我选用了广受好评的facebook出的flux,有不懂的可以自行百度一下,原则就一个“事件分发,单向流动”。

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(作用)" 命名的规则

//发送事件
functionsend_initData(){
//统一发送
//调用某个对象的信号
dispatcher.sendEvent("active","");
}

//切换专辑,重新请求
functionsend_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"

classSigDispatcher :public QObject
{
Q_OBJECT
public:
explicitSigDispatcher(QObject *parent = 0);

//注册事件
staticvoidaddRegister(SignalReceiver * );
staticvoidremoveRegister(SignalReceiver *);
staticvoidremoveAll();
signals:

public slots:
voidsendEvent(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>
classSignalReceiver
{
public:
SignalReceiver(){

}

public:
/**
* @brief 是否需要拦截
* @param cmd
* @return
*/
boolneedInvoke(std::string cmd){
std::list<std::string>::iterator j;
//遍历
for(j = cmds.begin();j!= cmds.end();j++){
if(*j == cmd){
returntrue;
}
}
returnfalse;
}

/**
* @brief 处理,
* @param cmd
* @param data
*/
virtualvoidinvoke(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){

}elseif (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
//加载专辑数据
functionloadAlbum(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"
classResultActionType :public QObject
{
Q_OBJECT
private:
explicitResultActionType(QObject *parent = 0);

public:
//单例
static ResultActionType& getInstance();

signals:
//激活
voidsig_active_success();
voidsig_active_error(int);

//分类
voidsig_get_category_success(QJsonArray);
voidsig_get_category_error(int);

//专辑
voidsig_get_album_success(QJsonArray);
voidsig_get_album_error(int);

//专辑详情

//音频
voidsig_get_audio_success(QJsonArray);
voidsig_get_audio_error(int);

//音频详情
voidsig_get_audio_info_success(QJsonObject);
voidsig_get_audio_info_error(int);
voidsig_get_current_progress(QString,QString,QString,QString);
voidsig_get_current_status(int);
voidsig_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
functiongetPlayList(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);
}


----------------------------------------------------------------------------------------------------------------------
我们尊重原创,也注重分享,文章来源于微信公众号:程序员学习分享录,建议关注公众号查看原文。如若侵权请联系qter@qter.org。
----------------------------------------------------------------------------------------------------------------------

鲜花

握手

雷人

路过

鸡蛋

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了