Qt for iOS,Qt 與Objective C混合編程

來源:互聯網
上載者:User

標籤:

 項目設定

既然要聊 Qt 混合 OC 編程,首先要簡單介紹一下 Objective C 。我只有一句話:Go,問搜尋引擎去。因為我所知實在有限,怕誤導了您。當然如果您不怕,往下看吧。

OC源檔案介紹

首先我要說一下 Objective C 的源檔案,尾碼是.m 或 .mm ,在 .mm 檔案裡,可以直接使用 C++ 代碼。所以,我們要混合 Qt 代碼與 OC 代碼,就需要在 Qt 項目裡加入 mm 檔案。

pro 檔案配置

Qt SDK for Mac ,安裝之後, Qt Creator 會使用 XCode 提供的編譯工具鏈來編譯代碼,能夠正確編譯 mm 檔案,也可以連結 iOS 的庫檔案。

而要混合 OC 代碼,需要更改一下 pro 檔案。一個是添加 mm 檔案,一個是串連針對 iOS 的庫檔案。

添加源檔案,使用 OBJECTIVE_SOURCES 這個變數,比如醬紫:

OBJECTIVE_SOURCES += ocview.mm
  • 1

連結庫 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
  • 1

好啦,關於 pro 檔案中與混合使用 OC 相關的配置項,大體就這些了。接下來我們看如何寫 Objective C 代碼啦。

混合使用Objective C 代碼

乖乖,很惶恐啊,這是我的弱項,沒寫過多少 OC 代碼。所以,請不要問我 OC 有關的問題,我真不知道……

背景

我的樣本,是在 QML 的介面上疊加iOS原生的介面,即 UIView、UIWindow之類的。因為 OC 是 C 的近親,和 C++ 有著天然的血緣,混合起來特別方便哈,比 Android 上使用 JNI 編程好用多了。

不過有一點, OC 都適用 [] 這種文法來調用函數,使用 XCode 的話,文法提示和自動完成功能非常強大,基本不用思考的就能找到你要用的函數。而 Qt Creator 麼,嘿嘿,就沒這麼好相與了,純粹要手寫哦。我當時都是開著 XCode 看 API 文檔找的,比較痛苦。

QQuickView 是什麼

我測試時的樣本,用的是 Qt Quick App 項目模板,使用 QQuickView 來載入 QML 文檔。這裡也以此為例來說明。關於Qt Quick,可以看我部落格的專欄,也可以看我的書《Qt Quick核心編程》,書裡系統詳細的介紹了Qt Quick的基本概念並提供了豐富的樣本。

首先要說 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 檔案內包含 OC 的標頭檔,與 C++ 標頭檔一個理兒,不過要使用 #import 哦。類似醬紫:

#import <UIKit/UIKit.h>#import <GLKit/GLKit.h>
  • 1
  • 2

包含了標頭檔,就可以使用 OC 類庫了。比如我要在 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,這就是全部了。

Qt for iOS,Qt 與Objective C混合編程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.