Qt那些事儿-序

公众号:张小飞那些事儿

公众号

前言

终于开篇了呢!
先写个前言吧。

一些经历

还是简单介绍下自己

我叫张小飞,目前在金山负责WPS For Linux的研发。

先说下自己的经历吧。刚毕业的我去了方正,当时维护一个桌面端阅读器的开发。名称是Apabi Reader 是个PDF+私有格式(CEBX)的阅读器

这个东西我维护了半年。现在回想起来。这个东西还是很有意思的。

Apabi Reader

凭印象说吧。先说GUI框架吧。当时这个软件的GUI框架是自己封装的。但是给我的感觉就是一个MFC+Win32API+GTK的集合。然后所有的编码没有任何规范,当时还改过几个Bug,而且还非常恶心,所以真的是见识到了什么叫恶心(垃圾)框架。

如果有对财务清楚的话,可能比较清楚,大家在打印发票的时候,使用的是PDF格式。近几年国家大力推荐国产项目,所以OFD标准出现了。最近发现一些公司报销已经开始使用OFD格式来报销了。下一个项目,应该就是OFD了。

OFD

大家都知道PDF格式的标准

PDF(Portable Document Format的简称,意为“可携带文档格式”),是由Adobe Systems用于与应用程序、操作系统、硬件无关的方式进行文件交换所发展出的文件格式。PDF文件以PostScript语言图象模型为基础,无论在哪种打印机上都可保证精确的颜色和准确的打印效果,即PDF会忠实地再现原稿的每一个字符、颜色以及图象。

这种不随着字体变化排版的格式是版式文档。PDF本质上是一个二进制流,也就是你没有办法去编辑。只能通过各种pdf编辑器来搞。
ofd,也是版式文档。不同的是,ofd本质上是一个xml的压缩包。跟office中的docx很像。

我的第二个项目就是负责OFD内核的排版引擎还有OFD阅读器的开发。技术选型当时是使用的跨平台框架GTK

GTK

当时由于项目原因,需要一个支持npapi的浏览器插件,记得当时研发组长选择了firebreath,这个跟gtk集成的很好,所以当时的项目选择了gtk。

GTK+(GIMP Toolkit)是一套源码以LGPL许可协议分发、跨平台的图形工具包。最初是为GIMP写的,已成为一个功能强大、设计灵活的一个通用图形库,是GNU/Linux下开发图形界面的应用程序的主流开发工具之一。并且,GTK+也有Windows版本和Mac OS X版。

gtk目前最新版本是gtk4.0。附上最近的更新日志(2020.12.18)

GTK 4.0 部分更新亮点:

  • 新的 widget 小部件以及对现有元素的重新设计
  • 集成媒体播放支持
  • 改进 GPU 加速功能(比如使用新的 Vulkan 渲染器)
  • 更好的 macOS 支持
  • 改进数据传输功能
  • 对着色器的重大改动
  • Vulkan 之外的 OpenGL 渲染改进
  • 更好的 Windows 支持

GTK目前在开源界使用的比较多,比如Linux上大名鼎鼎的Desktop-Gnome桌面

但是,写界面使用C语言的方式真的是太繁琐了,可以看下gnome下开机占用内存多少,我记得至少1G起步,所以deepin祖传了gnome的资源占用。(fork的gnome)。 然而Arch KDE(基于Qt)开机内存350M。虽然开机内存并不是完全GUI库的锅,但是这也恰恰说明了Qt的先进性。

当时觉得GTK做的界面太丑了(windows).所以我就自学了Qt,来重写了个PDF阅读器。
也是靠着这个项目,进入金山也算是一个加分项了。

GTK2Qt

可能很多人可能都知道,我在刚学Qt的时候,在github上使用Qt写了个PDF的阅读器。
代码在这里

https://github.com/CryFeiFei/Reader

当时受写GTK的影响,所以写了很多个内存泄漏的代码出来,GTK的控件创建啥的是不需要指定父类的,那时候也着急.所以也写了不少内存泄漏的代码(我的黑历史),也不准备改了。

简单对比下两个库的写的方法

以下代码都在Qt的源码中
D:\Qt\5.15.2\Src\qtbase\src\plugins\platformthemes\gtk3\qgtk3dialoghelpers.cpp

//gtk
GdkWindow *gdkWindow = gtk_widget_get_window(gtkWidget);

//Qt
QWidget* widget = new QWidget(parent);
信号

GTK中也有信号的概念,可以看下GTK是怎么绑定事件的。

//gtk
g_signal_connect(G_OBJECT(gtkWidget), "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);

//qt (Qt5还支持了编译期判断与函数指针)
connect(d.data(), SIGNAL(reject()), this, SIGNAL(reject()));

可以发现,gtk的代码依旧有着浓烈的c语言风格,用gtk写消息回调是很痛苦的,它不会有任何IDE的提示这个控件有对应的消息。以及资源需要手动管理,更有浓烈的指针强转,比如上面的代码G_OBJECT(gtkWidget);而Qt提供了区分于c++标准库的qobject_cast来专门用于控件转化。

这也是Qt为何从90年代到目前还是依旧有着很强的生命力。

小谈下GUI界面的资源管理

基于我自己的经验,我把这篇文章放到了这里。

众所周知,Qt是基于C++来拓展的一个GUI库。C++有的坑,在Qt中都会存在。

在Qt诞生的年代,并没有现代C++这么多特性,所以不得已,Qt造了很多自己优秀的轮子以及添加了很多自己的Features。

用很优雅的方式去解决了C++的很多痛点,针对GUI库的特性,又添加了很多有用的接口。

窗口资源管理

既然谈到C++,那最容易犯的错误之一那必然就是内存泄漏了。

最近这段时间,我也修复了WPS的不少内存泄露的问题。负责任的说,不管是多优秀的C++程序员,如果不注意,也是会写出来内存泄漏的。

Qt是一个GUI库,在程序员使用的时候,肯定会不可避免的去 对于这个问题,也有了自己的解决方案。

好在Qt在设计之初,就很好的解决了Widget控件的资源管理这个问题。
例子

一个简单的应用。

举个例子

比如我们在创建一个控件对象的时候。需要这样

Widget* pWidget = new Widget()

如果不释放,这个在堆上的空间就浪费掉了。

在使用完这个类之后,我们需要手动删除释放。

delete pWidget ;
pWidget = nullptr;

更高级一点的操作,那就是使用C++的RAII特性。这当然也是可以的。

理想很丰满,现实很骨感。事实上,我们的一个完整的GUI程序,对于所有的控件(比如窗体,按钮,画布)这种资源。如果都是这种手动管理的话,那是相当麻烦的。而且,啥时候释放,先释放谁,比如父窗口释放,其子控件资源怎么办。子控件释放,是不是还得通知父控件来删除掉其指针等等等。这样手动管理窗口资源的话

太TM浪费程序员心智了。

元对象的简单应用

所幸的是,Qt提供了元对象系统。其中的一个应用场景即:

只要继承QObject的类指定了父类,最后释放资源的时候,就不需要担心其资源问题。父类在释放资源的时候,子类会一起跟着删除。(当然你手动删除也可以,比如我想提前释放其资源。也没关系,Qt删除前会自动判断的)

Qt所有的基础控件,基本全都继承自QObject。比如QWidget

那么Qt的方法就是

QWidget* pWidget = new QWidget(parent)

其中parent就是其父控件指针。

当然你可能会疑问,如果,我就一个窗口,怎么可能会有父窗口呢。

QApplication,即Qt的主程序,也是继承自QObject的,如果没有合适的父类,父类指定为QApplication就可以了。

这样,我们就完美的解决了窗体控件内存泄露的问题。

本篇教程系列

本系列教程准备分为三个部分。

  • Qt的基础教程

  • Qt的高级教程

  • Qt源码剖析

我不准备把Qt的API都讲了,如果都展开,真的是篇幅太长了。我们要带着一个目的性的来学习一个新的框架。所以,我会带着目的性来给大家做几个桌面应用程序来一起学习Qt的相关API以及一些方法论。

我希望通过我的文章,能够给大家带来一些新的思路。

但是由于本人技术能力有限,难免本篇文章会有错误疏漏。希望大家给我多提一些意见。

公众号:张小飞那些事儿

公众号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值