关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » iOS开发 »Qt 与 Objective-C 的混合编程

    Qt 与 Objective-C 的混合编程

    2015-02-02 00:00:00 出处:oschina
    分享

    最近有好几个使用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,这就是全部了。

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    Destoon 模板存放规则及语法参考

    Destoon系统常量与变量

    Destoon系统目录文件结构说明

    Destoon 系统安装指南

    Destoon会员公司主页模板风格添加方法

    Destoon 二次开发入门

    Microsoft 将于 2026 年 10 月终止对 Windows 11 SE 的支持

    Windows 11 存储感知如何设置?了解Windows 11 存储感知开启的好处

    Windows 11 24H2 更新灾难:系统升级了,SSD固态盘不见了...

    小米路由器买哪款?Miwifi热门路由器型号对比分析

    IT头条

    Synology 对 Office 套件进行重大 AI 更新,增强私有云的生产力和安全性

    01:43

    StorONE 的高效平台将 Storage Guardian 数据中心占用空间减少 80%

    11:03

    年赚千亿的印度能源巨头Nayara 云服务瘫痪,被微软卡了一下脖子

    12:54

    国产6nm GPU新突破!砺算科技官宣:自研TrueGPU架构7月26日发布

    01:57

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    技术热点

    如何删除自带的不常用应用为windows 7减负

    MySQL中多表删除方法

    改进的二值图像像素标记算法及程序实现

    windows 7 32位系统下手动修改磁盘属性例如M盘修改为F盘

    windows 7中怎么样在家庭组互传文件

    Linux应用集成MySQL数据库访问技巧

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。