qt之qml與C++數據交互

我是一名Android開發出生,在大學學的是javaweb方向的開發,不能說javaweb方向的東西都精通,可是至少應該能撿的起來。由於我的的愛好「喜歡看到一些看起來炫酷的東西」因此開始了漫長的接近四年的開發之旅。也是由於工做的緣由,開始接觸linux的應用層開發。java

學習的心得:從android學習的過程當中,我明白了一件事,懂得站在巨人的肩膀上。在查詢資料的過程當中也發現,縱然qml的起源比android要早的多,可是網上關於qml的學習資料卻沒有android的多。做爲一名android過來的,我開始分享工做中接觸到的東西,但願對更多人有所幫助,試一次總結,也是一次分享。linux

記得有個門外漢,曾經問過我一個問題:「若是有個代碼倉庫,是否是全部的程序員都是從裏面根據本身的須要複製黏貼就能夠了?」 。個人回答是確定的,只是目前對於代碼倉庫的篩選與查找是咱們的工做。android

在我作Android的時候我發現,不少原來能夠從github上面找到的功能本身寫了還有一堆的bug,並且很是痛苦,因此真的建議你們在寫具體的功能以前,先去github上面找找,也許能幫助你。github上面能夠過濾語言,你們能夠過濾一下qml進行查看,目前基本上都是一些example。不過也很是的有幫助。c++

在我作公司安排的項目的時候,本着沿用android上面能夠複用的知識點的原則,架構方面我選用了廣受好評的facebook出的flux,有不懂的能夠自行百度一下,原則就一個「事件分發,單向流動」。git

qml界面和c++界面之間傳遞數據

qml與c++之間的交互自然的與flux架構一致。能夠直接套用,全部的事件經過信號進行分發。與android的EventBus差很少。程序員

qml傳遞數據給c++

通常用於傳遞qml【View】上面的一些操做。比方說點擊事件,請求發起事件等等。github

我使用的方式是,統一交給ActionCrateor.qml進行分發,這裏涉及qml的單例方式,能夠看這篇文章 要記得單例的使用要使用相對路徑,比方說我本地的代碼結構是 web

代碼結構
因此在別的目錄裏面使用就須要使用相對路徑

// /a/b/xxx.qml 相對於 /action/XActionCreator.qml的位置

import "../../action"

複製代碼

爲了保持一致,我這邊都是使用json進行傳遞,而不使用對象類型進行傳遞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
    }

}
複製代碼

此時須要在主入口處加上SigDispatcherbash

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);
}

複製代碼
相關文章
相關標籤/搜索