Diro's Journey

Programming Cooking Music Photography

https://blog.qt.io/blog/2013/04/15/evolution-of-the-qml-engine-part-1/

這一系列 QML engine 的文章(其實目前也只有一篇....)深入探討了 QML engine 的內部運作機制。Lars Knoll 指出了目前 QML engine 比較大的問題包括:

  1. Several object models
    1. 也就是一個 QML item 必需有3個object models,分別存在於 V8 engine, QML engine, Native Qt (以QObject 形式存在),不但耗費很多記憶體,要 sync 三個物件的值也是一大工程
  2. Bindings done through JS closures
    1. 每個 property binding 都是一個 JS closure,因此要先重新把 binding expression 重組成 JS closure,然後 V8 再 parsing 一次這個 closure。很慢,因此提出了一個輕量、快速的 V4 engine 來幫忙處理簡單的 expression(這也是為什麼官方的 performance tuning 文件叫你要盡量簡單化 binding expression)。
  3. Data type conversions
    1. Qt 跟 V8 之間的 data type 轉換很花時間,此外如果是 string 的話,memory copy 的成本也不低。當然,有些改善方法,但那就是拿記憶體或程式複雜度換來的了 
  4. QML scoping rules
    1. QML element 實際上是樹狀結構,跟傳統的 JS engine 其實不大一樣,QML engine 用了很複雜的方法來處理這段(through nesting slow and deprecated with() statements)。
  5. Throwing away QML type info
    1. type info 會被丟棄..
  6. iOS and WinRT support
    1. V8要求系統記憶體可以被設定成 executable,但這在iOS及WinRT是做不到的...所以只能另外做一套 JS engine 了..
  7. Working with upstream V8
    1. Qt 裡面的 V8 跟標準版的 V8 程式碼已經差很多了..而且好像很難 merge 了...

其中第2.點提到了 V4 engine,但是它在 5.4 的時侯,因為手誤,所以預設是沒有開啟 JIT 的(https://bugreports.qt.io/browse/QTBUG-43171),因此效能會比較差,請趕快換到 5.4.1 之後的版本吧 :)

在做自動化 UAT 時,最常做的事便是拿 HANDLE,這在以前傳統的 GUI Framework 只要用 Spy++ 或其它開發工具都很容易做到。

但現在 QML 不一樣了,QML 裡頭已經沒有所謂的 window handle,比較接近的是 objectName,你可以用 objectName 來對該元件進行操作(get property, call method…),問題是要怎麼樣拿到 objectName 呢?最直覺的作法就是直接看 QML source code,有錢一點的可能是用 Squish 之類的工具去做。但是直接看 QML source code 其實是比較花時間的,而 Squish 則是價格比較高,因此我實作了一個 JavaScript Library 可以讓你在 UI 上顯示每個 QML component 的 objectName。

例如你的 GUI Application 原本看起來是這樣:



在呼叫了 LabelQML.addObjectNameFlag(this); 之後,它便會在所有有 objectName 的元件上顯示一個小紅點:



當你滑鼠移至小紅點上方時,便會在畫面中央顯示它的 objectName:

完整程式碼及範例:

https://github.com/diro/LabelQMLComponent

其實作法很簡單,基本上就是 recursive 去列舉所有的 component,並檢查是否有 objectName,若有則建立一個 dynamic QML component(小紅點),當滑鼠移至小紅點時,便會在預先建立的 displayBoard 元件中顯示 objectName。

 

 

在上次為大家介紹 QML+Arduino 之後,最近也有人在介紹 Web +Arduino:

http://webduino.kktix.cc/events/web-arduino-20150321

在這裡講一下我自己的看法:

我不確定他的實作方式是不是在 Arduino 上跑 Web Server,然後由 Web Server 處理 url command 進而控制 Arduino.

我覺得以 Web 現在豐富的前端資源,確實可以很輕鬆的做出不錯的控制介面,如果有用 WebSocket,在一些數值讀取也可以做的非常即時。
此外它也原生具備了只要有browser就可以控制的優勢,而用 QML 還要提供各種平台的版本。

但如果在只有 serial port / bluetooth 的介面,要用 Web 控制可能就有點困難了。例如:一種應用是把 Arduino 當成 sensor,傳回各種感應資料,這時介面有可能會選用藍芽,而非一般網路介面。

而如果是用 QML 來做,因為可以引用 C++ 模組,所以介面上的選擇會比較彈性。不過現階段 QML 的資源比不上 Web,會讓新手或著要找現成元件的人比較辛苦。
不過 Web 終究需要一個 browser,也許可以用 QML Webview 來當成 browser,兩者可以相輔相成,用 Web 做 UI,用 QML/C++ 實作跟 Arduino 溝通的部份(在 QML Webview 中可以呼叫 C++ 功能,像 extension/plugin 這樣)

不過我覺得 QML 真的太簡單了,我還是喜歡用 QML 做 XD
例如 QML 中的 property binding,雖然用 Web 可以做到接近的語法(例 AngularJS 的 Data Binding),但寫起來可能還是沒有 QML 原生支援的那麼漂亮。

QML 要一個儀表板顯示環境亮度,只要一行:
Dial
{
value:arduino.brightness;
}

不過,還是老話一句,沒有最好的方案,只有最適合的方案 :)

這次在 hackathon.tw 的 QML 培訓課程跟大家介紹 LeapMotion 及 Arduino

QML 在硬體整合上也非常好用,主因是因為把相關硬體的 SDK 包裝成 C++ class 後就可以直接被 QML 操作,因上對 UX/UI 人員來講,要讀取/操控外部硬體都會非常簡單,例如我要讀取環境亮度,只要一行 arduinomgr.brightness 就可以,再加上 property binding,簡直如虎添翼 :)

QML + Arduino & Leap Motion from Diro Fan

這次在 hackathon.tw 中為 QML 做了初步的介紹,選定這個主題,主要是容易上手,而且初學者很容易做出一個很有感的成品,例如用 MediaPlayer、Camera 搭配現成的ShaderEffect,很容易做出很炫麗的作品。希望藉由這個介紹,讓許多新手也可以試試看 QML 這個比較年輕的架構:)

Qml 培訓課程 multi media from Diro Fan

IMG 3650

https://github.com/lemirep/QtLeapMotionLibrary

LeapMotion 算是這幾年在 User Interaction 領域上頗受注目的產品之一,提供的 SDK 也相當完整,而現在 github 上有個 QtLeapMotionLibrary 更是完整的把它的 SDK 包裝成 QML 元件供大家使用,讓 Qt 開發者在使用 LeapMotion 時又更加輕鬆寫意了 XDD

 

 請先照這三步安裝 SDK 及編譯 library:

  1. 安裝 SDK
  2. 將安裝完畢後的 SDK 中的 Leap 資料夾複製一份到 QtLeapMotionLibrary/QtLeapMotion/Leap 中,照這目錄結構放可以省掉不少調整 project file 的功夫。
  3. 不過原本的版本並不支援 Mac (project file 沒有處理mac build),因此請在各 example 中的 .pro 檔中加入粗體部份:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
linux-g++: {
    !contains(QMAKE_HOST.arch, x86_64) {
        LIBS += -L../../QtLeapMotion/Leap/x86/ -lLeap
        LIBS += -L$$OUT_PWD/../../QtLeapMotion/ -lQtLeapMotion
    } else {
        message("x86_64 build")
        LIBS += -L../../QtLeapMotion/Leap/x64/ -lLeap
        LIBS += -L$$OUT_PWD/../../QtLeapMotion/ -lQtLeapMotion
    }
}
 macx{ LIBS += -L$$OUT_PWD/../../QtLeapMotion/ -lQtLeapMotion LIBS += -L$$PWD/../../QtLeapMotion/Leap/lib -lLeap }

完成!現在可以開啟 example 來玩看看了 :)

Qt 原本就已經提供了 QTest 可以用來開發單元測試,但整體感覺還是沒有 google test 完整,因此實務上我們還是使用 google test 來進行單元測試。
Google test 搭配 Qt 一般來說有二點要處理:
1. Qt Signal
2. Event Loop
Qt Signal
因為你的 slots 沒辦法用 MOCK_METHOD 製造出來,或著說QObject::connect 無法連結到 MOCK_METHOD 做出來的偽slot ([苦主](https://groups.google.com/forum/#!topic/googlemock/RTgynKPa6ew))
因此,最好的方式仍舊是搭配 QTestLib 裡頭的 QSignalSpy 使用([前輩已經說過了](http://stackoverflow.com/questions/22390208/google-test-mock-with-qt-signals))。
QSignalSpy 可以幫助你檢查某個 signal 被 emitted 的次數,以及它每次 emit 所帶回的參數是什麼,算是蠻方便的:
QCheckBox *box = new QCheckBox(0);
QSignalSpy spy(box, SIGNAL(clicked(bool)));
box->animateClick();
EXPECT_EQ(1, spy.count())
QList<QVariant> arguments = spy.takeFirst();
EXPECT_TRUE(arguments.at(0).toBool());
不過,在用QSignalSpy的時侯要想一下,你有 event loop 嗎?不是每個unit test都像範例這麼單純的,如果你串起來不會動,就想想 event loop 吧 :)
Event Loop
因為許多功能都必需有 Qt 的 event loop 才能運作,因此勢必要呼叫 QCoreApplication::exec() 才能跑。那麼這個原本都是放在main()裡頭的 QCoreApplication::exec() 現在要放在那裡呢?當然就是放在每個 test case 之中了。
這邊的範例是我會呼叫 trackEvent() 功能,並等待 signal TrackEventFinished 回來時再離開 event loop:
TEST_F(PluginMixPanelFixture, Send_1_Event_With_Extra_Properties)
{
**int argc = 0;
QCoreApplication app(argc, NULL);**
auto conn = std::make_shared<QMetaObject::Connection>();
*conn = QObject::connect(pTestingPlugin, &PluginMixPanelClient::TrackEventFinished, [ = ]()
{
QCoreApplication::quit();
});

QString event = "[test] login function with extra properties";
static QVariantMap property;
property.insert("prop_size", 1000);
property.insert("prop_alias", "diro");
pTestingPlugin->TrackEvent(event, property);
**app.exec();**
QObject::disconnect(*conn);
}

在 hackathon.tw 的第二次培訓課程,我決定用遊戲製作來帶領大家進入 QML 的世界,理由跟上次一樣,先用這種馬上可以看到效果的,才能吸引大家的興趣。

QML 培訓課程 - 遊戲製作入門 from Diro Fan
Older Posts Home

ABOUT AUTHOR

Follow us

POPULAR POSTS

  • QML + Arduino / Web + Arduino
  • QML + LeapMotion & Arduino
  • [SOFT] TeamCity - 好用的 Continuous Integration 持續整合工具
  • How to Integrate Robot Framework with TestRail
  • [DECO] Eva Solo 花盆

Categories

  • 2016 5
  • agile 3
  • Bike 4
  • Book 4
  • Cooking 1
  • DECO3 4
  • House 8
  • Interior Design 4
  • IoT 1
  • IT 7
  • Life 13
  • Photography 1
  • Programming 22
  • QML 8
  • Qt 9
  • Scrum 3
  • Software 19
  • Travel 9
  • UAT 1
  • Uncategoried 3
  • 喇叭 1
  • 裝潢 6

FOLLOW US @ INSTAGRAM

About Me

Popular Posts

  • Odd-e LeSS@上海 後記 Part 4
    在 LeSS 最後一天,聽到別的公司在導入敏捷時,也成立了很多很多的實踐社群 CoP (Community of Practice),其中一個是 心靈成長 CoP,讓我印象非常深刻,這邊來聊聊為什麼 :) 在第五項修練中,彼得聖吉一直在強調"整體": 「遠古的人類並...
  • 單車路線#5 - 大坑缺溪-秀才窩自行車道-梅崗
    沿大坑 缺 溪騎到鎮南橋後,直走接往中庸路,經過一小段爬坡即接往福羚路,再往接瑞溪路即可抵達楊梅愛買後方,接著往裕成路(五楊高架下方)是我騎到楊梅最喜歡的路線。裕成路到底後,便到達楊梅校前路,是熱門的自行車路線,校前路前行便會抵達這條路線的重點-秀才窩自行車道,這個路線會穿過小茶...

Advertisement

Copyright © 2016 Diro's Journey. Created by OddThemes