一、關鍵類說明
qml內置了WorkerScript組件,該組件有一個source屬性,可以加載js文件,含有一個名為message的信號,意味着他有一個默認的onMessage槽函數,除此之外他還有一個方法,通過該方法可以給js文件中名為WorkerScript.onMessage的方法(在工作線程執行)發送消息,在次接收消息的函數體內部可以通過 WorkerScript.sendMessage的方式在發送消息給WorkerScript內置槽(在主線程執行),WorkerScript類的詳細說明如圖1所示
圖1 WorkerScript說明
二、示例效果分析
該示例程序總共包含2個簡單的WorkerScript使用方法,分別應用於timedisplay.qml組件和workerscript.qml組件
1、更新視圖數據
如圖2所示,是一個WorkerScript的簡單使用,qml文件通過WorkerScript對象向js函數發送一個消息,js函數中更新視圖內容,消息發送流程:ui線程->工作線程處理(調用接口更新ui)
圖2 更新視圖數據
視圖ui文件內容如下,每個2秒鍾timer定時器就會觸發,通過worker.sendMessage發送消息給js函數,這個js文件是通過WorkerScript對象的source指定,如下第17行代碼所示
1 Rectangle { 2 color: "white" 3 width: 200 4 height: 300 5 6 ListView { 7 anchors.fill: parent 8 model: listModel 9 delegate: Component { 10 Text { text: time } 11 } 12 13 ListModel { id: listModel } 14 15 WorkerScript {//在新線程執行操作,不阻塞ui線程,在父線程使用sendMessage發送消息 在子線程使用onMessage處理 16 id: worker 17 source: "dataloader.js" //加載js文件 18 } 19 20 // ![0] 21 Timer { 22 id: timer 23 interval: 2000; 24 repeat: true 25 running: true 26 triggeredOnStart: true//定時器開始執行一次 默認該值為false 定時器開始不執行 等過interval后才執行 27 28 onTriggered: { 29 var msg = {'action': 'appendCurrentTime', 'model': listModel}; 30 worker.sendMessage(msg);//在新線程里執行該操作 不阻塞ui線程 31 } 32 } 33 // ![0] 34 } 35 }
對應的js文件dataloader.js比較簡單,就一個函數,代碼如下
1 WorkerScript.onMessage = function(msg) { 2 if (msg.action == 'appendCurrentTime') {//如果是指定動作 3 var data = {'time': new Date().toTimeString()};//獲取當前時間 4 msg.model.append(data);//list添加新數據 5 msg.model.sync(); // 更新數據到ui 6 } 7 }
2、滾輪游戲
如圖3所示,是WorkerScript的一個更復雜的使用,就行文章開頭說的那樣,消息發送流程:ui線程->工作線程處理->ui線程
圖3 滾輪游戲
滾輪游戲的代碼比較簡單,在這里我就貼主要部分
1 WorkerScript { 2 id: myWorker 3 source: "workerscript.js"//指定js文件 4 5 onMessage: {//接收js文件發送的sendMessage消息 6 if (messageObject.row == rowSpinner.value && messageObject.column == columnSpinner.value){ //Not an old result 7 if (messageObject.result == -1) 8 resultText.text = "Column must be <= Row"; 9 else 10 resultText.text = messageObject.result; 11 } 12 } 13 } 14 //! [1] 15 Row {//水平方向上的兩個可以滾動的儀表框 16 y: 24 17 spacing: 24 18 anchors.horizontalCenter: parent.horizontalCenter 19 //! [0] 20 Spinner { 21 id: rowSpinner 22 label: "Row" 23 onValueChanged: { 24 resultText.text = "Loading..."; 25 myWorker.sendMessage( { row: rowSpinner.value, column: columnSpinner.value } ); 26 } 27 } 28 //! [0] 29 30 Spinner { 31 id: columnSpinner 32 label: "Column" 33 onValueChanged: { 34 resultText.text = "Loading..."; 35 myWorker.sendMessage( { row: rowSpinner.value, column: columnSpinner.value } ); 36 } 37 } 38 }
其中Spinner是自己封裝的一個組件,導出了當前文本和當前索引兩個屬性,對於的js文件如下
1 var cache = new Array(64); 2 for (var i = 0; i < 64; i++) 3 cache[i] = new Array(64); 4 5 function triangle(row, column) { 6 if (cache[row][column]) 7 return cache[row][column] 8 if (column < 0 || column > row) 9 return -1; 10 if (column == 0 || column == row) 11 return 1; 12 return triangle(row-1, column-1) + triangle(row-1, column); 13 } 14 //! [0] 15 WorkerScript.onMessage = function(message) { 16 //Calculate result (may take a while, using a naive algorithm) 17 var calculatedResult = triangle(message.row, message.column); 18 //Send result back to main thread 19 WorkerScript.sendMessage( { row: message.row, 20 column: message.column, 21 result: calculatedResult} ); 22 } 23 //! [0]
js文件就不多說了,本篇示例主要就是想分析下WorkerScript的使用,通過上邊兩種使用方式基本就能理解