我是一名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++之間的交互自然的與flux架構一致。能夠直接套用,全部的事件經過信號進行分發。與android的EventBus差很少。程序員
通常用於傳遞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
}
}
複製代碼
此時須要在主入口處加上SigDispatcher
bash
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
複製代碼
以上就能夠將全部的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怎麼傳遞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)) } } 複製代碼
傳遞給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;
}
複製代碼
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會致使顯示不出來。
#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);
}
複製代碼