發表文章

目前顯示的是有「Qt」標籤的文章

產品開發玩技術很過癮!實作 QML 動畫背景!

圖片
由於最近在開發自己的產品,又開始重操舊業,開發起 Linux 系統的相關應用和嵌入式技術。為了這個產品,精心開發了一個使用者介面,除了動手把驅動程式搞定、圖形化介面搞定,也調教效能、改善系統架構。 開發自己的產品很過癮,愛怎麼搞就怎麼搞!於是,看到死板的背景覺得很不舒服,就在思考是否可以跑個動畫背景呢? 因為使用的是 QML 技術來開發 UI,最直接的想法,就是用 QtMultimedia 的 MediaPlayer 無限循環播放一個影片,當作動畫背景: MediaPlayer { id: bg; source: 'bg.mov'; loops: MediaPlayer.Infinite; autoPlay: true; } VideoOutput { anchors.fill: parent; source: bg; } 當然,我們選擇的背景影片,是一個開頭跟結尾一樣的影片,如果正確循環播放,會無縫接軌的變成一個順暢的動畫背景。 然而,結果不如預期,碰到了一個問題,那就是每當背景影片播放到最後時,會畫面變成全黑,然後才再一次重新開始播放,沒辦法「無縫接軌」。仔細暸解以後,發現 MediaPlayer 元件是 QMediaPlayer 的 QML Type 實作,所有秘密都藏在 QMediaPlayer 之中。因為 QMediaPlayer 預設所有的通知事件,都是固定以 1000ms(1秒)的頻率來觸發,這代表,當 QML 元件發現影片播完時,通常已經是播完以後的事了,所以畫面一定會因為影片結束而變黑,然後 QML 元件才發現影片結束,重新進行播放。 知道緣由後,我們可以從事件更新頻率下手,讓 QML 元件發現影片播完的時間更接近實際影片結束的時間,但這必須動用到 C/C++ 的實作,因為 QMediaPlayer 的事件更新頻率無法以純 QML 的方法修改。 C/C++ 完整應用程式的實作如下,我們把更新頻率調高為每 100ms 一次: #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQuickWindow> #include ...

OwaViewer 釋出!不用安裝肥滋滋的 Qt 也可以開發 QML!

圖片
在國內,很多人或許對 Qt 很陌生,但這一直是筆者近年來想要推廣的技術,尤其是 QML 這個自 Qt Project 衍生出來的新 UI 技術,更讓人著迷。具有原生效能和擁有炫麗效果的 QML ,確實是一個打造產品的好東西,如大家近來所聽到的 Tesla 汽車、Jolla 手機等,其 UI 就是使用 QML 所開發。當然,之前舊文章中所展示的 UI 和介面,以及能跑在 Android 手機上的 OwaNEXT,也有不少是結合 QML 技術所開發。 推廣過程中總有人質疑,覺得 QML 不是一個設計師能學會的東西。事實上,它的語法相當簡單且模組化,所以也聽聞一些國外的設計公司,其設計師都直接用 QML 做出 UI ,再交給工程師去接上功能。這也是為什麼 HanGee 國民機在開發手機和各種裝置的 UI 時,要選用 QML 為底層的原因了。 因此,筆者自己的公司最近也在籌備許多課程和分享,也與許多朋友成立了一些社群(你可以在 Facebook 加入我們的 Qt @ Taiwan 社群),並設計開發一些相關的工具,以協助更多人能更快速進入到 QML 的世界。不過,因為 UI 與設計師更密切相關,近期應該會針對不懂技術的設計師,推出許多相關的 UI 開發課程。(如果你對這樣的技術有興趣,歡迎與我們聯絡) 其實,這次的黑客松活動與 HanGee 社群合作開設 QML 課程就是一個嘗試,也想收集一些 Qt/QML 初入門者狀況和資料。其中發現一個最大的問題是,無論是技術還非技術人員(如設計師),在安裝 Qt 時就會碰到各種狀況,而且 Qt 開發環境因為功能繁複且龐大,安裝一整套下來要花上不少時間,在學習上也就是一個阻礙。這對技術人員來說,可能不是什麼大問題,但這對設計師來說,就是一個極大的挫折。 因此,我們、講師和 HanGee 社群合作,開發了一個新的工具『OwaViewer』。原本這個工具只是被設計來開發 HanGee 手機介面,但現在可以用來讀取和執行一般的 QML 檔案。這意味著,你再也不需要安裝 Qt 和學習一堆知識,就可以使用 QML 開發使用者介面了,也可以很容易提供一個成果給客戶直接操作,這對許多設計師來說應該是個好消息。 OwaViewer 是個 Open Source Proje...

Node.js 的原罪,和 QML 的不合作運動

在上個星期剛結束的 OSDC.tw 2014 活動上給了一個 Talk ,提及用 Node.js 結合 QML 來開發應用程式,讓我們可以使用 Node.js 和 JavaScript 來寫 QML 元件,不需要再使用 C/C++。事實上,這樣的技術看起來簡單,但實際上是困難重重。 其實,要做 Qt 的 Node.js binding,有很多問題要克服,最直接的不外乎是 Event Loop,Node.js 本身是 JavaScript 語言,所以有自己的事件引擎,而 Qt 是一個圖形界面的 Toolkit,一樣也有自己的事件引擎,因此,我們要再解決一次與過去整合 GLib 一樣的問題(詳見舊文: 探究如何整合 GLib Main Event Loop 和 Node.js 的 libuv ),只不過這次要實作的是 Qt 的 QAbstractEventDispatcher。 為了讓 Node.js 可以順利驅動 Qt,筆者之前花了一些時間研究,所以有了一個實驗性質的 Project 『 Brig 』在 Github,也為了 Qt 重新寫了一個新的 libuv 版本的 EventDispatcher。很幸運的,在實作完新的 EventDispatcher 後,已經可以順利的將 Node.js 和 Qt 的 Event Loop 接起來。 但別高興的太早,還有個大問題存在。Qt 5.2 之後將 QML 內的 V4 JavaScript 換成了 Google V8 JavaScript Engine,並且為了一些特性,修改了 V8 的部份實作。很不巧的是,Node.js 的核心也是 V8,這意味著,如果我們使用自己的 Node.js Binding 去建立 QML Engine,程式會馬上崩潰並結束(Segmentation Fault)。 種種問題,你可以說這是 Node.js 的原罪所致,這也是為什麼相當難幫 Qt 寫一個 Node.js 的 Binding,你在 NPM 上也根本找不到良好的 Qt Module 存在。最終我們的做法,還是修改了 Node.js 的部份程式,才能將他們整合在一起。

【COSCUP 2012】閉幕!簡報釋出!

國內一年一度最大的開放原始碼(Open Source)活動,再次順利落幕。很多人都意猶未盡,所以每當活動結束,便會開始思考明年要分享什麼、反省今年哪裡做的不夠,有人會在活動過後的連續幾天,電腦上開著簡報編輯器,盯著空白的內容,靜靜的發著呆。可惜的是,最後總是因為沒有任何想法而放棄。一直到了明年 COSCUP 的徵稿消息發出,一堆人又開始拾起空白了近一年的想法,擠出一個題目,逼著自己在一兩個月內完成,上台發表。就如同學校的期中、期末考,沒有死到臨頭,大多數同學都沒有唸書的動力,也不會激發自己 120% 的腦力和體力。所以,Event-Driven 的開發模式,一直是在很多開發者促使自己進步的方式。 別以為兩個月時間很充足,大家都有外務、有工作、要過生活,所剩的時間實在有限,所以每當到了 COSCUP 的前夕,總是會聽到很多講者在拼命趕工的聲音。其實,這樣都還算是常態,頂多拼命一點,少睡一點,都還可以頂得過去。可是,今年一次給『兩個 Talk』,就真的讓人會虛脫到不行,還好,熱情能戰勝一切。:-) 由於今年活動承辦的分工方式比較特殊,所以被選上了兩個稿,分別是: JavaScript 全面逆襲!使用 Node.js 打造桌面環境! 用最潮的 JavaScript 盡情開發 KDE/Qt 程式 前者是總結這一年來,我們團隊所開發出來的各種 Node.js APIs,並整合成為一個如同 GNOME/KDE 的桌面環境(Desktop Environment),並展示使用 JavaScript 開發出來的 Juice Desktop Environment(果汁桌面環境)。後者則是為符合 KDE 的議程方向,探討使用 Node.js 開發 Qt 程式的可能。 後記 退學不是件好的事情,請勿模仿。:-S

【企業顧問咨詢】為您的產品選擇作業系統解決方案

你將為自家的產品,選用什麼樣的作業系統?我想,這年頭,不外乎是 Android。但是,可能不是最佳選擇。 我想大多數人都會同意,由於智慧型行動裝置的掘起,Google Android 在業界大放異彩,使用 Linux 作業系統核心的 Android,實現了許多華麗的UI,也讓眾多廠商取得入門門票,有機會與 Apple iOS 一爭長短。許多人都相信,未來是 Android 的天下,除了手機要用 Android,電視要 Android,救人一命的醫療器材也要用 Android,所謂的 Android anywhere 是終極目標。 不過,經過這幾年下來,許多人發現這不過是我們資訊科技業一廂情願,有太多的領域是難以使用 Android,如工控市場等,無論是以穩定、價格、移植維護成本考量的因素,都可能是無法使用 Android 的重點。因此,如今要選擇作業系統解決方案,又變成一個需要思考的難題。 筆者擔任顧問時,每當面對客戶躊著於這個問題時,我總問他們幾個大問題: 你們的產品用途是否單一且單純?是否要有讓使用者自行上網安裝其他第三方軟體的擴充性? 你們的產品是否為消費行電子產品?是否需要高可用行和高穩定性? 你們的軟體需要有華麗特效的 UI 嗎?你們現在擁有的人員有哪些開發 UI 程式的經驗? 有網路的需求嗎?如果有,需要哪些需求?Ethernet、Wifi、3G? 計劃中的產品硬體規格? 有多少規模的人可以參與開發? 很明顯的,對於手機和行動裝置業者是這樣的答案:(他們都會選用 Android) 用途不單一,需要讓使用者任意自行上網安裝軟體。 是功能複雜的消費性電子產品,所以客戶多多少少能接受偶爾當機 UI 需要有華麗的特效。開發人員都熟悉並使用 Java 的經驗。 有所有網路的需求。 擁有一定等級以上或是當前最頂級的 ARM 處理器。 最少數十個,多半是上百人甚至上千人的研發人員。 如果你是『非手機』和『非行動裝置』業者,你的產品可能不完全具備這些條件。建議您,一旦有任何一點不具備,請慎重考慮是否使用 Android 還是有機會選擇其他的解決方案。 而當前的解決方案主要常見有三種: Android Linux + Qt Framework Linux + Own Application 限於篇幅,太細節的評估無法一...

發瘋的 Qt QWS TTY Keyboard Driver

最近接了一個小案子,主要是協助客戶將 Qt 應用程式從舊板子移植到新的硬體上,由於硬體是 Third-party 做,當然所有的驅動程式也是由別人處理,我們並不經手,只和硬體廠商密切合作。 這次我們碰到了一些 Keyboard 問題,一開始是 Linux driver 缺少 input_sync() 的操作,導致 Qt 無法正確辯別按鍵的『壓放』。接著碰到個更棘手的問題,就是 Qt 送到應用程式的 Key 事件(Event)有很大機率會送錯。這將導致按鍵所觸發的結果,有很大的機會我們無法預期。檢查過 evdev event 和其發出來的 keycode,我們確定了 Linux Driver 是正確的,判斷應該是 Qt 的問題。 經過一番檢查後,發現是因為 Qt-Embedded 預設使用 TTY Driver(qkbdtty) 去驅動鍵盤,大部份情況下不太會有問題,但因為我們走的是標準的 Linux evdev (/dev/input/eventX),如果很快速或多重觸發鍵盤按鍵,就有可能讓 Qt 的 TTY Driver 取樣和解析出錯誤的 Event 值。最快的解決辦法就是捨棄 Qt TTY Driver,然後改用 Qt  LinuxInput Driver(qkbdlinuxinput)。 不過 qkbdlinuxinput 並不處理 VT,這是與 qkbdtty 最大的差異,此舉會造成板子上的 Console 不正常切換,Debug 用的 Console 會因此壞掉。筆者在此對 QWS Keyboard Driver 做了些修改,讓 tty driver 使用 linuxinput driver 的方式去解析 keyboard event,並保留 VT 的處理機制。 Patch 檔案連結如下: http://fred-opensource.googlecode.com/git/patches/qkbdtty_qws.patch

針對『電子紙』優化 Qt 繪圖事件

最近手上有一些電子紙的案件,指定使用 Qt 做為圖型平台。與一般裝置不一樣的地方,電子紙的更新頻率很低,平均下來每秒頂多刷新一次,相對於 LCD Panel 的每秒 60 次起跳,實在低的可憐。對於專職繪圖的 Qt 而言,要如何壓低刷新的頻率和確認畫面繪圖完成,最後再推入 Display,便是一個重要的課題。 壓低更新頻率比較單純,透過修改 Framebuffer Driver 就可以達成。此外,也必須利用 setUpdatesEnabled() 和 update() 盡量避免 Qt 連續多次的繪圖需求,合併一次送入 framebuffer,這樣可以減少 Qt 來不及畫完和畫面閃爍的問題。 到此為止只是改善顯示效果和基礎的建置,真正要完成完美的一次推送,通常需要使用電子紙驅動程式所提供的額外 API,它同意我們自己決定何時將 Framebuffer 的資料推送到紙上。 至於何時該將畫面推送至電子紙上?這時需要針對 QApplication 做一些修改,監聽和自己創造一個新的事件: const QEvent::Type UpdateScreenEvent = (QEvent::Type)1234; bool Application::notify(QObject *obj, QEvent *e) {      if (e->type() == UpdateScreenEvent) {           if (updateScreen) {               EPaperDriverCtrl *ctrl = (EPaperDriverCtrl*)EPaperDriverCtrl;               ctrl->pushFBtoPanel();               updateScreen = false;  ...