关闭 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,这就是全部了。

    上一篇返回首页 下一篇

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

    别人在看

    Edge浏览器百度被劫持/篡改怎么办,地址后边跟着尾巴#tn=68018901_7_oem_dg

    Google Chrome 在 iPhone 上新增了 Safari 数据导入选项

    Windows 11专业版 KMS工具激活产品密钥的方法

    DEDECMS安全策略官方出品

    Microsoft Text Input Application 可以关闭吗?

    新版本QQ如何关闭自带的浏览器?

    C++编程语言中continue的用法和功能,附举例示范代码

    c++ map 的数据结构、基本操作以及其在实际应用中的使用。

    C语言如何避免内存泄漏、缓冲区溢出、空指针解引用等常见的安全问题

    C语言中的break语句详解

    IT头条

    马斯克2026最新采访总结:2040年,全球机器人数量将突破100亿台

    23:52

    专家解读|规范人工智能前沿业态健康发展的新探索:解读《人工智能拟人化互动服务管理暂行办法》

    00:54

    用至强 6高存力搞定MoE卸载!

    17:53

    美国将允许英伟达向中国“经批准的客户”出售H200 GPU

    02:08

    苹果与微信就15%手续费达成一致?腾讯未置可否

    22:00

    技术热点

    PHP 和 Node.js 的10项对比挑战

    Javascript闭包深入解析及实现方法

    windows 7、windows 8.1手动增加右键菜单功能技巧

    MYSQL出错代码大汇总

    windows 7假死机怎么办 windows 7系统假死机的原因以及解决方法

    Ubuntu(Linux)下配置IP地址的方法

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

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