Qt for iOS,Qt 与Objective C混合编程

转自:https://blog.csdn.net/foruok/article/details/43351137

因为我写了一系列Qt的博文以及一本书《Qt on Android核心编程》,最近有好几个使用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,问搜索引擎去。因为我所知实在有限,怕误导了您。当然如果您不怕,往下看吧。

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
    
    

链接库 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 文件中与混合使用 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>
    
    

包含了头文件,就可以使用 OC 类库了。比如我要在 QQuickView 上面创建一个新的 iOS 原生的 UIView ,.mm 文件里可以这样:

void addOCView(QQuickWindow *w)
{
    UIView *view = reinterpret_cast<UIView *>(w->winId());
CGRect  viewRect = CGRectMake(<span class="hljs-number">10</span>, <span class="hljs-number">10</span>, <span class="hljs-number">100</span>, <span class="hljs-number">100</span>);
UIView* myView = [[UIView alloc] initWithFrame:viewRect];
[myView setBackgroundColor:[UIColor colorWithRed:<span class="hljs-number">1.0</span> green:<span class="hljs-number">0.0</span> blue:<span class="hljs-number">0.0</span> alpha:<span class="hljs-number">1.0</span>]];
[view addSubview: myView];

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

如你所见,我写了一个 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(<span class="hljs-string">"qrc:/main.qml"</span>));
viewer.show();

addOCView(&amp;viewer);

<span class="hljs-keyword">return</span> app.<span class="hljs-keyword">exec</span>();

}

一点儿都不惊喜是吧,就是直接调用了 addOCView 哦。哈哈,确实如此了。

iOS 原生界面与 QML 元素的位置映射

混合使用 iOS 原生界面时,也可以达到原生界面与 QML 界面的无缝集成。关键就在于计算 QML 界面元素的位置,然后根据 QML 界面元素的位置来设置原生界面的位置。

QML元素位置换算

QML 提供了换算元素位置的方法,Item 有个方法,叫作 mapToItem() ,它可以把一个相对于 Qt Quick Item 的区域映射到另一个 Item 上,得到坐标了。比如你的 qml 文件是下面的样子:

Rectangle {
<span class="hljs-keyword">...</span>

Rectangle {
    id: videoLayer;
    anchors.margins: <span class="hljs-number">8</span>;
    anchors.left: parent.left;
    anchors.right: parent.right;
    anchors.top: parent.top;
    anchors.bottom: actionBar.top;
    color: <span class="hljs-string">"green"</span>;
}

<span class="hljs-keyword">...</span>

}

你想把原生的 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);
 
 
  • 1
  • 2

换算出的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,这就是全部了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt for iOS是一款专为iOS平台开发应用程序的软件开发框架。Qt是一种跨平台的开发工具,它允许开发者使用一套代码在不同的操作系统上创建应用程序。Qt for iOS则是专门针对苹果公司的iOS操作系统的开发框架。 Qt for iOS具有许多优点。首先,它使开发者能够轻松地开发具有现代化用户界面的应用程序。Qt for iOS提供了丰富的UI组件和样式,使开发者能够创建出漂亮且用户友好的应用程序。 其次,Qt for iOS具备高度的可移植性和跨平台性。开发者可以使用相同的代码在iOS和其他操作系统上进行开发,减少了开发工作量和维护成本。这为开发者节省了宝贵的时间和精力,并且能够更快地推出新的版本和更新。 此外,Qt for iOS还提供了许多功能强大的库和工具,例如网络通信、数据库访问、图形处理等。开发者可以利用这些工具快速构建出各种复杂的应用程序。 然而,Qt for iOS也存在一些局限性。首先,由于iOS平台的封闭性,Qt for iOS在某些方面可能无法完全与苹果的开发工具集成。这可能会导致一些功能和特性的限制。 另外,使用Qt for iOS开发应用程序需要一定的学习成本。开发者需要掌握Qt框架和相应的工具,以及了解iOS平台的开发规范和限制。这对于初学者来说可能是一项挑战。 总体而言,Qt for iOS是一种强大且灵活的开发框架,可以帮助开发者快速构建出现代化的应用程序。它在跨平台和可移植性方面具有优势,但也需要一定的学习成本并可能受到一些限制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值