Qt 與 Objective-C 的混合程式設計
最近有好幾個使用Qt的朋友問起 Qt for iOS 的事情,因為我在這方面的經驗特別少,寫不出系統的文章來,非常抱歉,不能給出令人滿意的答覆,推薦大家去看 Jason’s Home ,在我部落格左側邊欄的友情連結裡也有,他提供了 Qt for iOS 的一些非常有意義的文章,而且是基於實踐的,他的 App 已經在 App Store 中上線。
至於我呢,在這篇文章裡,簡單介紹一些如何混合 Qt 與 OC 程式設計。
我要說的內容呢,大部分在 Qt 幫助裡都有,請大家到索引模式下,鍵入”Qt for iOS”,找到 Qt for iOS 這篇文章來看。它介紹了搭建開發環境、編譯應用、混合OC程式設計這三個方面,已經非常詳細了。
如果你不想啃英文,那可以接著我的文章往下看。
專案設定
既然要聊 Qt 混合 OC 程式設計,首先要簡單介紹一下 Objective-C 。我只有一句話:Go,問搜尋引擎去。因為我所知實在有限,怕誤導了您。當然如果您不怕,往下看吧。
Objective-C原始檔介紹
首先我要說一下 Objective-C 的原始檔,字尾是.m 或 .mm ,在 .mm 檔案裡,可以直接使用 C++ 程式碼。所以,我們要混合 Qt 程式碼與 Objective-C 程式碼,就需要在 Qt 專案里加入 mm 檔案。
pro 檔案配置
Qt SDK for Mac ,安裝之後, Qt Creator 會使用 XCode 提供的編譯工具鏈來編譯程式碼,能夠正確編譯 mm 檔案,也可以連結 iOS 的庫檔案。
而要混合 Objective-C 程式碼,需要更改一下 pro 檔案。一個是新增 mm 檔案,一個是連線針對 iOS 的庫檔案。
新增原始檔,使用 OBJECTIVE_SOURCES 這個變數,比如這樣子:
OBJECTIVE_SOURCES += ocview.mm
連結庫 XCode 提供的庫,則需要使用 QMAKE_LFLAGS ,類似這樣子:
ios { QMAKE_LFLAGS += -framework OpenGLES QMAKE_LFLAGS += -framework GLKit QMAKE_LFLAGS += -framework QuartzCore QMAKE_LFLAGS += -framework CoreVideo QMAKE_LFLAGS += -framework CoreAudio QMAKE_LFLAGS += -framework CoreImage QMAKE_LFLAGS += -framework CoreMedia QMAKE_LFLAGS += -framework AVFoundation QMAKE_LFLAGS += -framework AudioToolbox QMAKE_LFLAGS += -framework CoreGraphics QMAKE_LFLAGS += -framework UIKit }
上面是我使用 Qt 針對 iOS 程式設計的配置。我使用了很多針對 iOS 的庫,所以新增了很多 framework 。
“ -framework UIKit ”這種引數,是經由 Makefile 傳遞給 Clang 的引數,-framework 是用來指示要連結某個框架(或者說庫)的關鍵字,它後面跟的是框架(庫)名。
需要注意的是,我們使用針對 iOS 的庫,不是通過“ LIBS += ”這種方式來引入哦。當然,你自己通過 Qt 實現的 .a 庫,依然需要使用“ LIBS += ”這種方式。
指定plist檔案
有時你需要為你的專案指定 plist 檔案, plist 檔案全名是 Property List ,字尾是 .plist 。它用來定義 iOS 應用的屬性,比如 Bundle(iOS上的一個應用被稱為一個 Bundle ) 的顯示名字、可執行檔名字、簽名、證書等等,當然也可以儲存一些配置資料。具體的介紹參考 iOS 開發的文件吧。
要在 pro 檔案裡新增 plist ,要使用 QMAKE_INFO_PLIST 關鍵字。如下面這樣子:
QMAKE_INFO_PLIST += MultiWindow.plist
好啦,關於 pro 檔案中與混合使用Objective-C 相關的配置項,大體就這些了。接下來我們看如何寫 Objective C 程式碼啦。
混合使用Objective C 程式碼
乖乖,很惶恐啊,這是我的弱項,沒寫過多少 Objective-C 程式碼。所以,請不要問我 OC 有關的問題,我真不知道……
背景
我的示例,是在 QML 的介面上疊加iOS原生的介面,即 UIView、UIWindow之類的。因為 OC 是 C 的近親,和 C++ 有著天然的血緣,混合起來特別方便哈,比 Android 上使用 JNI 程式設計好用多了。
不過有一點, OC 都適用 [] 這種語法來呼叫函式,使用 XCode 的話,語法提示和自動完成功能非常強大,基本不用思考的就能找到你要用的函式。而 Qt Creator 麼,嘿嘿,就沒這麼好相與了,純粹要手寫哦。我當時都是開著 XCode 看 API 文件找的,比較痛苦。
QQuickView 是什麼
我測試時的示例,用的是 Qt Quick App 專案模板,使用 QQuickView 來載入 QML 文件。這裡也以此為例來說明。
首先要說 QQuickView 到底是什麼。
QQuickView 呢,其實是一個 UIView 。UIView 則是 iOS 開發框架裡很多介面元素的根兒,比如 UIWindow 就是 UIView 的子類。
Qt 的 QQuickView 是一個 UIView ,建立了 QQuickView 例項後,就有了一個 UIView ,然後 Qt 玩了一些魔法,拿到了 UIView 的 OpenGL Context ,跑起了 Qt 的事件迴圈,在這個 OpenGL Context 上從零開始繪製了自己的場景和 UI 系統。
就這麼簡單,你可以查閱 Qt 原始碼來進一步瞭解。
需要注意的是, QML 介面元素的渲染,與 UIView 這種原生介面的渲染,不在一個執行緒中。而且 iOS 對 OpenGL ES 的支援很好,你可以同時使用多個 OpenGL Context 。更好的是,你可以視窗模式來建立一個 OpenGL Context 。不像 Android 版本哦, Qt 使用 OpenGL 的時候都是全屏模式,區域性更新不支援,所以我們在 Android 上使用 QML 裡的 Camera 和 VideoOutput 來開發拍照應用時, VideoOutput 必須是全屏模式(必須fill_parent)。而在 iOS 上,則沒有這個限制了。看來 iOS 還是很美好的啦。
我靠,扯得有點兒遠,最近寫技術文章少了,越來越羅嗦了。言歸正傳吧。
因為 QQuickView 實際上就是一個 UIView ,所以可以強制轉換為 UIView ,然後使用 OC 的方法來建立新的 UIView 或者 UIWindow ,這樣就有了原生的 UI 元件了,你可以在這個原生的 UI 元件上使用 OpenGL 繪製自己的東西或者新增其它原生的控制元件,非常美好。
不過要說明的是,通過這種方法建立出來的 iOS 原生介面元素,會始終在 QML 介面之上,把 QML 場景裡的介面元素給蓋住。
混合程式碼
要使用 OC 的類庫,需要在 mm 檔案內包含相關的標頭檔案,又有幾部分工作要做。一個是在 pro 檔案里加入 SDK 路徑,使用 INCLUDEPATH 變數即可,不多說了。另外一點是在 mm 檔案內包含 Objective-C 的標頭檔案,與 C++ 標頭檔案一個理兒,不過要使用 #import 哦。類似醬紫:
#import <UIKit/UIKit.h> #import <GLKit/GLKit.h>
包含了標頭檔案,就可以使用 Objective-C 類庫了。比如我要在 QQuickView 上面建立一個新的 iOS 原生的 UIView ,.mm 檔案裡可以這樣:
void addOCView(QQuickWindow *w) { UIView *view = reinterpret_cast<UIView *>(w->winId()); CGRect viewRect = CGRectMake(10, 10, 100, 100); UIView* myView = [[UIView alloc] initWithFrame:viewRect]; [myView setBackgroundColor:[UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0]]; [view addSubview: myView]; }
如你所見,我寫了一個 addOCView 方法,它的引數是 QQuickView 。在 addOCView 方法裡,我把 QQuickView 強制轉換為 UIView 來使用。
我建立了一個新的 UIView ,設定了它的背景顏色,然後把它新增為 QQuickView 的子視窗。諾,就這麼簡單了。
說下 main.cpp ,看它如何使用 addOCView() 方法。程式碼如下:
int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQuickView viewer; viewer.setResizeMode(QQuickView::SizeRootObjectToView); viewer.setSource(QUrl("qrc:/main.qml")); viewer.show(); addOCView(&viewer); return app.exec(); }
一點兒都不驚喜是吧,就是直接呼叫了 addOCView 哦。哈哈,確實如此了。
iOS 原生介面與 QML 元素的位置對映
混合使用 iOS 原生介面時,也可以達到原生介面與 QML 介面的無縫整合。關鍵就在於計算 QML 介面元素的位置,然後根據 QML 介面元素的位置來設定原生介面的位置。
QML元素位置換算
QML 提供了換算元素位置的方法,Item 有個方法,叫作 mapToItem() ,它可以把一個相對於 Qt Quick Item 的區域對映到另一個 Item 上,得到座標了。比如你的 qml 檔案是下面的樣子:
Rectangle { ... Rectangle { id: videoLayer; anchors.margins: 8; anchors.left: parent.left; anchors.right: parent.right; anchors.top: parent.top; anchors.bottom: actionBar.top; color: "green"; } ... }
你想把原生的 UIView 定位到 id 為 videoLayer 的元素內部,可以類似下面換算一個座標並使用它:
var coordinate = videoLayer.mapToItem(null, 8, 8, videoLayer.width - 16, videoLayer.height - 16); winUtil.addUIView(coordinate.x, coordinate.y, coordinate.width, coordinate.height);
換算出的coordinate有 x 、 y 、 width 、 height 屬性。當 mapToItem 的第一個引數為 null 時,換算的結果就是相對於 QQuickView 的。那我們在新增 UIView 時,就可以用這個換算結果來構造一個 CGRect 物件,用這個 CGRect 來初始化 UIView 的位置。
設定 UIView 的位置
前面示例程式碼中的 winUtil 是我在 C++ 內實現的一個輔助類,匯出到了 QML 環境中。它的 addUIView 方法根據傳入的座標來設定原生 UIView 的位置。參考程式碼如下:
UIView *v = reinterpret_cast<UIView*>(view->winId()); uiw = [[UIWindow alloc] initWithFrame:CGRectMake(x, y, width, height)]; [v addSubview: uiw];
上面程式碼中,view 是 QQuickView 。這次我們建立 UIView 時使用了傳入的 x 、 y 、 width 、 height,這樣新建的 UIView 就和 QML 元素整合在一起了,看起來好像是一體的。
OK,這就是全部了。
相關文章
- XCode 中 Swift / Objective-C / C / C++ 混合程式設計XCodeSwiftObjectC++程式設計
- CUDA 8的混合精度程式設計程式設計
- 【IDL】 IDL與C#混合程式設計技術C#程式設計
- C++:與C混合程式設計 CMake undefined reference toC++程式設計Undefined
- QT QML模組的程式設計挑戰與解決方案QT程式設計
- C++ & Intel MKL 混合程式設計C++Intel程式設計
- Groovy + Java 混合程式設計方案:GMavenJava程式設計Maven
- QML之C++混合程式設計C++程式設計
- QT QML模組的程式設計藝術QT程式設計
- Objective-C 執行時程式設計指南-介紹Object程式設計
- 【混合程式設計】C/C++呼叫Fortran的DLL程式設計C++
- Qt程式設計師必看/關於Qt收費的官方答覆QT程式設計師
- FFT原理及C++與MATLAB混合程式設計詳細介紹FFTC++Matlab程式設計
- 學習 Qt 程式設計的好書精品推薦!QT程式設計
- OC/Swift/C/C++混合使用的程式設計姿勢SwiftC++程式設計
- Qt Creator程式設計之正規表示式QT程式設計
- 程式設計師程式設計時的簡單方法與技巧程式設計師
- 一個在 Objective-C 和 Swift 中實現剖面導向程式設計的故事ObjectSwift程式設計
- QT硬體介面設計QT
- 【Tensorflow_DL_Note14】TensorFlow視覺化學習1-Tensorflow與OpenCv混合程式設計視覺化OpenCV程式設計
- Anno 讓微服務、混合程式設計更簡單(Net love Java)微服務程式設計Java
- 《Objective-C 高階程式設計》乾貨三部曲(三):GCD篇Object程式設計GC
- cuda程式設計與gpu平行計算(四):cuda程式設計模型程式設計GPU模型
- 結對程式設計的利與弊程式設計
- Qt混合Python開發技術:Python介紹、混合過程和DemoQTPython
- Objective-C設計模式——中介者Mediator(物件去耦)Object設計模式物件
- 《Python程式設計練習與解答》之程式設計概論Python程式設計
- Objective-C 與 C++ 的異同ObjectC++
- 中國程式設計師與美國程式設計師寫程式碼的區別分析程式設計師
- ARM彙編和C語言混合程式設計中陣列的陣列的操作C語言程式設計陣列
- 為什麼 qt 成為 c++ 介面程式設計的第一選擇?QTC++程式設計
- 鴻蒙程式設計江湖:ArkUI 的宣告式 UI 程式設計與狀態管理鴻蒙程式設計UI
- 開源專案 Qt Esay Designer (Qt視窗設計器)QT
- 程式設計師與醫生程式設計師
- 《說文解字》與程式設計程式設計
- 2024 計算導論與程式設計程式設計
- 碼農與程式設計師的區別程式設計師
- 幽默:遊戲程式設計與其他程式設計完全不同? - hillelogram遊戲程式設計
- 混合現實設計:火星計劃頭戴裝置配套應用的設計心得