C++是非常流行、强大、常用的编程语言,非常适合用在系统级编程、硬件交互、运行效率高等特点的场景。在测试系统这类测试、测量领域中,充满了硬件交互、高性能等要求,非常适合使用C++。
图形界面库Qt是用C++编写的跨平台图形界面库,在军工、航空、航天、工业应用等领域中非常流行,在使用C++编写程序时,非常适合使用Qt编写图形界面。
基于C++的应用程序,通常是C/S模式的本地应用程序,但这些年非常流行基于浏览器的B/S软件,为此在本章的最后也讨论C/S软件与B/S软件,比较二者的特点。
C++的英文全称是C plus plus,意为C的超集,它在C的基础上加入了面向对象的支持。在面向对象编程思想出现时,在C的基础上增加了面向对象的特征,便成了C++,所以C++向后兼容C,向前支持面向对象编程,C++的编译器都会有选项按照Cpp编译或者按照标准C编译。
C++是C的继承,它既可以进行C的过程化程序设计,也可以进行以继承和多态为特点的面向对象的程序设计。C++既擅长面向对象程序设计,又可以进行基于过程的程序设计,因而用C++可以编写多种场合的软件。
C++不仅拥有计算机高效运行的实用性特征,而且还致力于提高大规模程序的编程质量与程序设计语言的问题描述能力。
与其他流行的编程语言比较,C++具有如下显著区别。
(1)C++是编译型语言,这是与流行的Python、JavaScript等脚本语言之间的显著区别。
(2)C++编译后得到计算机可直接执行文件,这是与Java、C#等依赖运行时环境的语言间最显著的差别。
C++的内容庞大、复杂、深奥,已有大量书籍对其进行过详细介绍。本节从使用者的角度讨论程序设计语言C++的特点。
(1)C++是面向对象的编程语言,拥有面向对象编程的诸多特征,如类、对象、多态、封装、继承等。它以面向对象编程的方式编写程序,具有高度抽象的能力,能够编写各种复杂场合、复杂业务逻辑的软件。
(2)因为C++面向硬件、兼容C、直接访问内存地址,所以在面向底层硬件的场合,C++可以像C一样快速、高效、易用。
(3)用C++编译程序后,生成可直接在操作系统上运行的二进制程序,可直接运行,不需要运行时环境、运行时解释器。基于C++编写的软件,不依赖运行环境,更加灵活、适应性强。
(4)泛型编程可以在编译时展开、生成具体代码,相比链接库函数的调用方式,会少很多函数调用,从而使执行速度更快。
(5)C++的标准库简单、轻量,没有很多复杂的库函数,C++的标准库可以使C++更易于掌握、更易于使用。C++的标准库,大都采用了泛型编程、编译时展开的机制,进一步提升了C++的运行时效率。
(6)C++的一个显著特点是追求高效,和其他语言比较,运行时的高效是C++最重要的优势。
(7)C++与其他编程语言比较的特点如表3-1所示。
表3-1 C++与其他编程语言比较的特点
1.开发环境
通常,在Windows操作系统中编写、调试、运行C++,可以使用微软的开发工具Visual Studio(简称VS)和VC编译器,也可以使用Qt Creator和MinGW编译器,它们都是比较好用、易用的开发环境、编译器。
2.现代C++
自C++发布C++98后,C++标准沉寂了很多年,最近这些年快速发布了几个版本,包括C++11、C++14、C++17、C++20、C++22,新增和修订了很多内容,力图追赶其他高级语言,C++从一个古老的编程语言近乎成为全新语言。这些更新确实加入了很多内容和特性,使C++更加现代化了。
从C++11到C++22称为现代C++。现代C++的新特性都围绕C++之父指明的两条主线:一是直接硬件映射,二是零开销抽象。这也正好体现了C++的蜕变方向:更快、更好用。
现代C++在C++98基础上进行了很多改进,令作者印象深刻的改进如下。
(1)新增了关键字auto:在某些情况下,auto很好用,如定义map的迭代器。在C++98中要写很长的类型,而用auto后只需要写4个字母,非常便捷。在编写、阅读代码时往往需要知道具体的类型,而在使用auto后,需要分析才能知道具体类型。
(2)新增了匿名函数lambda表达式:在某些情况下使用,可以避免加入很多函数。
(3)新增循环访问foreach:可以方便地循环访问数组元素,这是现代的编程语言都具备的循环访问。
(4)标准库中有很多更新:加入了正则表达式、线程、并发操作等。因为有些人认为C++的标准库内容太少,所以在这些年的C++更新中大量增加了标准库内容。
3.流行度
程序设计语言经过多年发展,出现了很多新语言。在使用量方面,在Java出现的头几年,抢走了很多C++使用者,导致C++用户量大大下降,之后到现在,C++用户量一直很平稳,没有大的起落,C++仍然拥有很多稳定的使用者。
4.编写健壮的C++代码
由于C++复杂,编写代码容易出错、对开发人员要求较高,所以有很多C++编码准则。普通C++使用者应该避免使用复杂的C++特性,因为普通C++使用者花在使用高级特性的时间、精力远远大于问题本身,应该把时间和精力用在理解软件的业务逻辑上。在多数情况下程序员不应该在语言层面耽误太多时间。
编写C++代码,要基于防御式编程的方法,可以减少程序异常出错的风险。防御式编程(Defensive Programming,来源于 Code Complete 即《代码大全》)。防御式编程的主要思想是:子程序不应该因传入错误数据而被破坏,哪怕是由其他子程序产生的错误数据。其核心思想是:要承认程序会有问题,程序都需要被修改。聪明的程序员应该根据这一点来编程序。
C++有诸多的特点,在实现测试系统框架时应基于如下考虑。
1.面向硬件、高效
C和硬件打交道比较方便,能直接操作物理地址、寄存器,C++兼容C也可以方便操作硬件。例如,在很多定制化的总线板卡中,板卡的驱动程序使用C编写,提供的驱动库也是C函数库,使用C++编写应用程序,可以方便调用这些驱动库。
C++执行效率高,没有影响运行时效率的环境依赖、内存回收器,能够有面向对象编程的高度抽象能力,编写复杂应用程序,又能面向硬件高效运行。
能有效使用硬件和管理高度复杂性的应用程序,这是C++不可替代的优势。
2.交流的需要
技术人员在工作(包括嵌入式开发、逻辑程序开发)中经常需要和其他技术人员交流、对接调试。技术人员都会使用C进行通信调试、对接调试,掌握兼容C的C++可以方便地和其他人交流。对于很多名称概念,如定义数据结构、位域、高位低位、字、双字、字节序等,C和C++的技术人员会很熟悉。
3.如何解决弊端
在使用C++的情况下,应遵守C++的编程准则,执行编程规范,以提高设计、编码的健壮性。在这方面有很多具体措施,大量的有关C++的书籍描述如何正确使用C++。
下面介绍简单、易用的具体方法。
(1)从设计的角度,减少复杂设计、测试驱动设计、充分模块化、积极设计测试用例,为方便编写测试代码做一些设计。
(2)从编码的角度,执行一套编码规范,防御式编程。
(3)有效设计对象的生命周期、作用域。谨慎地使用new,在编程过程中的很多时候没必要使用new。必须使用new时再使用。
4.编程本身很复杂
有人认为:软件是人类有史以来最复杂的发明。
软件可以随意地编写创造,根据个人意志生成、修改,这导致了软件从需求、功能、设计、编码的每个步骤都很复杂。
编程代码本来就很复杂,为了性能、面向硬件,可以使用C++。如果只是做普通应用程序,没有高效、硬件访问等要求,可以避免使用C++。
Java是这些年最流行的编程语言,也确实有很多优点,C++程序员使用Java后,一定会被Java程序的流畅所折服。相反,如果Java程序员使用C++,则一定会大吐槽。
C++的程序需要由程序员自己设计层次,太依赖于程序员的编码水平。若将大量代码文件都放到一层目录中,没有区分子文件夹、没有层次,则不好区分软件模块结构,这很不友好。相比之下,Java中包的概念就好很多,若会用Java则一定会用包,所以写得再烂的Java程序,也能分清层次,若是C++的烂程序,则基本没法理解了。
相比之下,Java中包、异常机制、单一继承等,从语言层面已经约定好、强制写程序的人利用好的编码习惯,而在C++中这些是编码准则,需要完全依赖于程序员的个人水平,很落后。就好像学习C++的人,花了大量时间学习语言本身,然后又要学习C++编程规范,之后用几年时间将这些规范变成自己的编码习惯,而使用Java的程序员,在学完语言本身后,编写的程序已经具有了良好的风格。
Java与C++各有其特点。C++与Java的主要比较如表3-2所示。
表3-2 C++与Java的主要比较
由于Java具有内存回收机制,可以随意地写new创建对象,导致很多程序员不再关心运行效率。然而,创建对象、申请系统的资源等操作,相对耗时进而影响程序的运行效率,这也是很多Java程序运行慢的根本原因。
在Java中为了提升运行时的性能,采用一种专门的技术(称为性能调优)对已有的Java代码进行改进。Java性能的根源在于内存回收机制,即便经过性能调优后,Java程序的执行效率仍然不会比C++高。
编程语言有很多,也有很多批评C++的声音。
关于编程语言好坏的讨论永远是程序员社区中最激烈的争论。Linux创建者就十分讨厌C++,经常在开源社区发文痛斥C++。也有很多人痛斥C++复杂、容易出错。而那些拥护C++的人进行反驳的一条理由是:很多C++使用者的水平低导致用不好C++。人各有所好,各抒己见,众说纷纭。
C++是C的升级版,这也导致了C++有些不伦不类。为了兼容C,C++没有完全面向对象编程,一些面向对象的特性实现得不够良好。例如,在C++中没有所有类的基类Object。Java于20世纪90年代出现,Java中各种优良的设计使大量程序员蜂拥而至,直到现在,Java仍然是很多人使用的编程语言。
1.C++的缺点
C++被大量开发者批评,C++的缺点如表3-3所示。
表3-3 C++的缺点
同时,C++中有很多概念、内容,相比其他语言确实内容庞大。编程语言复杂度比较如图3-1所示。
图3-1 编程语言复杂度比较
从图3-1可以看出,C++是个大胖子,非常臃肿。Java是一个健康的青年,不胖不瘦刚刚好。C是个瘦子,没什么肉,就像C一样概念少。
2.用C++编写的软件是否稳定
有些人说用C++编写的软件不稳定。软件是否稳定和编程语言没有关系,用其他编程语言编写的软件也会有崩溃现象。软件是否稳定、可靠视程序员而定,和编程语言无关。
可能的原因是:C++不强制要求捕获异常,软件中出现内存访问等异常时,会直接进入操作系统层面的异常处理中,操作系统会直接关闭软件,而没有有效的提示,进而导致用户觉得软件不稳定。Java等语言内置异常处理机制,所有的异常都会进入Java的异常机制中,给用户的感觉更友好。
3.少数人的自娱自乐
这些年,由于C++不断地更新、加入新特性,更加暴露了C++的缺点:C++更加复杂。面对C++的复杂,很多人认为C++已经变成了少数人的自娱自乐。多数程序员不需要使用高级、复杂的特性,绝大多数的软件代码不需要这样写,不使用这些特性也行。
4.C++是否会消失
C++本身确实有一些问题,然而人们也认可其优点。并且,大量的工业基础软件、生产工具软件是用C++开发的,如Chrome浏览器的核心V8引擎、三维引擎OpenGL。在很多要求高性能、高实时性的应用场景中,也要求编程语言具有一定的抽象能力,C++是首选,如工业控制软件。
纵观来看,C++不可能消失,只不过其应用领域越来越窄。
Qt是用C++编写的跨平台图形用户界面应用程序开发框架,从20世纪90年代后期到现在,已经稳定流行20多年,在世界各地各种应用程序中都经受了考验、验证。
Qt是Linux操作系统中事实上的图形界面标准库。在Windows操作系统中,基于C++开发图形界面程序,在有跨操作系统运行需求时,首选也是Qt。
很多国产化操作系统选用Qt作为图形界面开发工具,特别是军工等领域对国产化操作系统需求量大,也导致Qt的使用量非常大。
在Qt的官方主页中,包括嵌入式领域、桌面应用领域、手机端开发,这些都是Qt可以应用的领域。在各类桌面应用程序中也有大量基于Qt的应用程序,如流行的国产化办公软件金山WPS就是用Qt编写开发的,编写移动应用程序的国产开发工具套件HBuilder也是用Qt开发的。
在流行度、稳定性、易用性等方面,Qt表现优秀。
经过多年的发展,Qt已经非常稳定、可靠、流行。Qt已从一个小众的界面库成为图形界面开发领域的主流。
1.优点
(1)源码跨平台:源码可在Windows/Linux等操作系统中编译、运行,这是重要的一个优点。一次编写,四处编译,在国产化的大背景下,该优点尤其重要。
(2)容易使用:Qt非常容易使用,开发人员经过简单学习就能掌握。简单阅读几个Qt类代码,就会发现Qt中的每个类名称、接口函数名称都是容易记忆和调用的。其源码目录层级结构清楚,很容易定位到需要的类库。
(3)提供开发套件:Qt配有开发工具套件Qt Creator,其功能丰富、强大、跨平台,能在Windows、Linux等操作系统上使用,并且在各自操作系统中的表现一致。
(4)丰富的例子:Qt内置了大量、完整的示例代码。示例代码可以直接编译、运行,在编写代码实现软件功能时,可以参考示例的源码,然后自己实现功能。
(5)文档齐全:Qt的帮助文档Assist中有丰富的资料,其解释齐全、丰富,非常有用。
(6)不只具有图形界面库:除提供图形界面功能外,还包括大量其他功能组件,如网络编程组件、XML组件、脚本引擎组件、跨平台的数据库访问组件等。
2.人员要求
使用Qt不需要有高深的C++知识,只要掌握C++基础知识,语法、类、继承、多态、指针等就可以使用Qt,在Qt Creator中建立界面工程,编写图形界面软件,做一些小型图形界面软件项目,随着经验的增加,可以参与复杂系统的开发。
3.Qt很好用
在使用Qt的过程中,会发现Qt充分考虑了程序员的感受,提供了丰富的类,类命名、函数命名、库命名非常友好,各个类的接口方法也非常丰富,例如:
(1)QWidget中的接口函数有:父窗口函数、子窗口函数、坐标转换函数、事件函数。
(2)QPainter绘图函数中:重载了几十种绘图函数。
很多库非常好用,如封装的QAbstractSocket近乎涵盖网络通信中用到的所有操作,其他还有文件操作的QFile、文本流操作的QTextStream等。
4.界面美化
参与过Web界面开发的人员很清楚,可以用一套样式表CSS(Cascading Style Sheets,层叠样式表)搞定界面美化,用CSS指定控件颜色、背景图标、渐变色、图标等可见的外观。Qt的界面也可以用一套样式表来改变外观,Qt的样式表语法与Web中CSS基本一致。使用Qt自带的Qt设计师(QtDesigner)工具,通过用鼠标拖放控件、设置布局、设置控件属性、填写CSS,就能完成一个美观的界面,不需要任何编码。
5.缺点
Qt的缺点是:一些库的执行效率低,如Qt网络编程库不适合用于高速数据接收;脚本引擎执行效率也不高。但是这些影响不大,多数软件无太高的性能指标,如果要写一个高速通信的代码,网络接收部分则不能调用Qt的网络通信模块。
6.弥补C++标准库的不足
Qt是图形界面库,在Qt中也有大量的非界面功能的类,如线程类、Socket通信类、编码类等,正好弥补了C++标准库中缺少的内容。
这些基础的类(如QString、QByteArray、QFile、QTextStream等)封装了开发中常用的操作,比C++标准库中的接口方法更加丰富,这些类非常好用。Qt中的常用模块举例如表3-4所示。
表3-4 Qt中的常用模块举例
7.跨平台
需要跨平台的首要原因是国产化,国家战略层面一直在推行国产化,作为基础软件的操作系统是重点,在各类国产操作系统中,图形界面开发又以Qt为主。然而,我们平时使用的很多软件只允许运行在Windows环境中,为了满足既能运行在Windows环境中又能运行在各类国产操作系统中的需求,使用Qt开发软件可以支持跨平台编译、运行。
在应用场景方面,必然是用C/C++编写高速、实时通信的应用程序,此时的图形界面框架只能使用Qt。如果采用前、后台分离原则,用C++写后台,用其他语言写前台,显然增加了设计的复杂度。在Linux或者VxWorks环境中运行的很多图形界面都是使用Qt开发的。
8.嵌入式设备
Qt的官方网站主要介绍在设备(如移动端、车辆等)上的优势。诺基亚手机、塞班操作系统中各种应用程序都是使用Qt开发的。诺基亚手机流行了很多年,然而在安卓(Android)系统遍天下的今天,Qt也支持安卓等移动平台中的软件开发,并且Qt在一些领域中也很流行。
Qt至今发展了20多年,从早期的Qt1到最近的Qt6已经有了6个大的版本号,Qt版本不断更新并增加了很多新的特性,这些特性不断改进、丰富Qt库,使Qt越来越好用、越来越强大。发展到现在,Qt中有两条并行的界面开发技术线:一是基于QWidget方式开发界面,二是基于QML(Qt Meta-Object Language,Qt元对象语言)方式开发界面。
这两种界面开发方式的差别非常大:一种是基于C++代码,另一种是基于描述性格式文件。这是完全不同的两种界面开发方式,所以是两条技术线。两者各有特点、适合的应用场合。
1.QWidget方式
QWidget属于传统界面开发,和VB/VC/Delphi等拖放控件开发类似。在Qt的各个版本中都可以基于QWidget方式开发界面。在QWidget内部调用操作系统的绘图函数,从头绘制界面,采用QWidget方式时,使用C++编写代码操作控件、各种QWidget对象,实现界面功能,这是QWidget最本质的特征。
QWidget意为小部件,是用户界面的原子:它从窗口系统接收鼠标、键盘和其他事件,并在屏幕上绘制自己,每个小部件都是矩形的,它们按顺序排列,小部件由其父部件和它前面的小部件剪裁。
本书中使用的Qt界面开发,是基于QWidget的方式。
2.QML方式
在Qt4.7及后续的Qt5中,Qt官方主推QML技术。QML是QtQuick技术的一部分,用一定的格式来描述一个程序的用户界面,而不是编写C++代码实现界面。在QML中,一个用户界面被指定为具有属性的对象树,用描述性的语言描述界面,而不是编写严谨、规范的C++代码,这使得Qt更加便于很少或没有编程经验的人使用。
QML是一种声明式编程语言,并且是Qt框架的一个组成部分。QML的主要功能是让开发人员快速、便捷地开发出用户界面,这些界面包括桌面应用、移动设备和嵌入式应用的界面。另外,QML还能够与JavaScript无缝整合一起开发使用,即在QML代码中可以使用JavaScript代码。
在Qt4.8中建立的QtQuick项目中的QML文件示例如下。
这些年,移动端、互联网移动应用火热,Qt针对这类应用特点推出QML技术。QML旨在帮助开发者创建在移动电话、媒体播放器、机顶盒和其他便携设备上的,使用越来越多的直观、现代、流畅UI的工具集合。
3.比较
QWidget和QML各有优势:QWidget传统、中规中矩,QML新颖、时尚。它们都是很强大、可靠的技术。在应用领域方面,QWidget主要集中在传统行业,如金融、军工、安防、航天、船舶、教育等领域;QML主要集中在移动端、互联网领域,如汽车仪表、直播、车载软件等领域。
因为本书的测试系统是应用在传统行业的一套应用软件,所以采用了Qt的QWidget方式,作为主要技术路线。
MFC是个老古董,是一个Windows操作系统中C++的界面库,曾经是Windows上的界面开发主流框架。其他C++/C界面框架的流行度都不高,并且也比较小众,如C风格的GTK、C++的wxWidgets。也有一些界面框架是基于MFC再封装的界面库,如Xtreme Toolkit、BCG等,然而这些类库仍然是MFC,依赖MFC的原理机制。
在C++的界面库中,选择MFC进行对比。
MFC基本理念是对Windows的原始API函数再封装。由于Windows的API接口是用C编写的,所以MFC编程风格有些类似C风格,即没有完全的面向对象设计。而基于图形界面程序库的软件往往是描述现实世界的,最好的方式是按照面向对象的理念进行充分封装,而MFC在这方面做得不好,导致MFC难以使用。
大部分C++程序员做界面都曾经使用VC/MFC,那些无处不在的各种宏、各种ID、ID对不上导致的各种问题,调整控件位置不停地调用MoveWindow函数等,即便使用MFC第三方的界面库,不管那些界面库多么高级,都没有改变MFC本身的设计问题。
MFC与Qt的主要对比如表3-5所示。
表3-5 MFC与Qt的主要对比
除C++的各类界面框架外,其他编程语言的图形界面框架也有很多,下面罗列一些与界面相关的技术,与Qt进行对比。
1.C#的WinForm
Windows中最常用的莫过于.Net环境的WinForm、WPF,对应WPF在Qt中有类似的QML技术。应将QWidget与WinForm进行比较,WinForm确实很易于开发界面,入门也简单。下面以Qt的QWidget方式和C#的WinForm进行比较,找出的缺点如下。
(1)WinForm不是开源界面库,使用多年WinForm之后仍不知道原理,不会知道WinForm的各种效果如何实现,在遇到问题时,无法根据源码推导出解决方案。而在Qt中,实现一些复杂的效果时可以跳到Qt的源码中,参考源码、弄懂原理,然后自己实现。
(2)WinForm中的控件属性编辑窗口中的属性太多且没有层级,很难被定位、使用,一些控件有属性,另一些控件没有属性,让人搞不懂、疑惑。Qt中的控件属性编辑窗口,有一层一层的基类继承关系,可以知道控件的属性、信号是哪个基类的,很容易记忆、使用。
2.安卓应用程序界面开发
缺点是:安卓的界面支持图形化拖放、布局、控件、样式等,编辑完界面后,需要手写代码,将界面中的控件通过ID绑定到代码中的对象,这需要手写代码。Qt的qMake自动生成代码、生成对象,自动将控件ID(Object Name)绑定到对象,相比之下,安卓要落后一些。
3.Web界面HTML开发
缺点是:没有好的可视化编辑方式,在Web前台界面的HTML开发中,多数的开发方式是手写前台界面中的各种HTML标签元素、表单等,然后在浏览器中运行查看效果,没有好用的可视化编辑工具。与其他图形界面开发比较,其开发效率、调试效率低一些。有些复杂的界面会有界面专职美工设计,但对于多数开发者,仍然是手写HTML代码、用浏览器运行看效果的,没有主流的面向程序开发者的可视化界面工具。
在本书的测试系统框架中,Qt是应用的核心技术。本节首先介绍从搭建开发环境到基本使用,接着介绍Qt的重要概念等内容,作为Qt使用入门。
1.基础
Qt好用易学,掌握C++是掌握Qt的基础,应先学习好C++基础,之后找一本关于Qt的书籍,阅读且掌握前面基础的几章就够用,然后是实践,在实际项目中多用Qt,调试程序、查看Demo、使用Assist,多用就可以掌握、用好Qt。
推荐阅读《C++GUI Qt 4程序设计》(第二版)。
掌握如下基本内容,可以事半功倍。
(1)使用Qt Creator:Qt Creator是集成开发工具,可先使用Qt Creator编辑源码,然后编译、调试、运行程序等,还要掌握一些常用快捷键。
(2)使用Assist:Assist是安装Qt后的帮助文档,其中包括多个手册,借助Assist可使用索引和查询帮助、查询出示例代码,然后可以打开示例代码、编译、运行示例。
(3)使用Demo:Demo是Qt安装后的示例程序,可以找范例、源码,编译、执行范例源码工程。
(4)使用Qt设计师:设计UI界面,包括拖放控件、设置布局、修改属性、连接信号和槽等。
2.集成开发环境
基于Qt开发应用程序,要使用集成开发环境,既可以使用微软的Visual Studio,也可以使用Qt官方提供的Qt Creator。推荐使用Qt Creator,这是Qt提供并推荐使用的开发工具,是专为Qt开发的集成开发工具,其功能丰富,也易于使用,在Windows、Linux上的表现一致。如果开发的应用程序需要跨平台编译、执行,使用Qt Creator不需要修改任何工程文件,就可以在Windows、Linux中打开Qt Creator工程文件、编写代码、编译运行、调试代码,掌握Qt Creator的快捷键可以提高工作效率。
Qt Creator在Windows操作系统、Linux操作系统等环境中,其外观、使用等表现均一致。在Qt官方网站的下载页面中,有Windows、Linux等操作系统的Qt Creator可供下载使用。Linux环境的Qt Creator如图3-2所示。
图3-2 Linux环境的Qt Creator
有多种方式可供搭建Qt的开发环境,可以自己下载Qt源码,自己用编译器编译生成静态库、动态库,可以使用Qt提供的编译好的安装包。在最近的更新中,Qt也提供了在线安装方式。
在Qt官网的下载页面中,有很多的Qt版本可供使用,可以根据自己的情况选择下载安装。用早期版本Qt搭建开发环境会有些麻烦。
1.Qt4环境搭建
基于VC编译器的Qt4开发环境,需要执行几个步骤,包括安装Qt Creator、安装对应VC编译器的Qt包,然后运行Qt Creator,在Qt Creator的“选项”对话框中,设置构建和运行的编译器、Qt版本、路径等内容。Qt Creator 3.6的“选项”对话框如图3-3所示。
图3-3 Qt Creator 3.6的“选项”对话框
2.基于opensource的开发环境
一些版本的Qt中提供了opensource文件,可以直接安装。例如,在Qt官方网站的下载页面中选择Qt5.5版本,定位到qt-opensource-windows-x86-mingw492-5.5.0.exe选择下载该文件,执行顺序安装,在安装过程中会提示选择安装的编译器、Qt组件等步骤,Qt5.5 opensource安装设置如图3-4所示,可根据需要选择安装,安装完毕之后可将编译器、Qt库、Qt Creator等全部安装上,之后直接启动Qt Creator就可以编写、调试Qt程序。
图3-4 Qt5.5 opensource安装设置
3.在线安装
自Qt5.15版本和Qt6全系列开始,对于个人非商业版本,也就是开源版本,Qt不再提供已经制作好的操作系统下的离线安装包,安装Qt有以下两种选择。
(1)下载编译源码:例如qt-everywhere-src-5.15.2.zip,但是编译过程烦琐,需严格遵循编译步骤,且花费数小时的时间。
(2)在线联网安装:基于Qt提供的在线安装工具,安装步骤相对简单,顺序执行安装即可,所以推荐在线安装的方式。
使用Qt开发应用程序的主要步骤:创建工程、添加并编辑界面、添加响应函数。之后,编写业务代码、调试并运行程序。
在复杂工程项目中有很多软件模块,有的设计为动态库,有的需要作为控件。此时,不是一个单一的可执行程序。在这种情况下,使用Qt Creator的“子目录”项目,在其中建立主程序、自定义控件、静态库、动态库等项目,多人协助开发。应对复杂的软件设计,一定会用到框架化、Qt插件开发等,对此将在后续章节中说明。
1.创建工程
在Qt Creator的主界面菜单栏中有创建工程菜单,按照步骤一步一步地顺序执行,建立一个图形界面工程,即可编译、运行。在新建工程界面中,有多种类型的模板可供选择。在如图3-5所示的Qt Creator 3.6的“New File or Project”对话框中有Qt Widgets Application(界面QWidget应用)、Qt Console Application(命令行应用)、Qt Quick Application(QtQuick应用)等,可根据需要选择模板。
图3-5 Qt Creator 3.6的“New File or Project”对话框
2.添加并编辑界面
编辑界面的核心思路是,使用Qt设计师即QtDesigner。Qt设计师是可视化的界面设计工具,在Qt Creator中已经集成了Qt设计师,也可以单独启动Qt设计师,在其中编辑UI界面。在Qt设计师中编辑UI界面,如图3-6所示。
(1)新建QWidget工程后,会自动添加一个MainWindow界面,Qt Creator主界面会打开Qt设计师的编辑界面窗口,编辑新建的UI文件,在Qt Creator左侧的控件视图(Widget Box)中,可以拖曳控件到UI界面中。
(2)用鼠标选中控件,在属性窗口(属性编辑器)中会显示该控件的属性,根据需要在属性窗口中将控件的属性值改为自己想要的属性值。
图3-6 在Qt设计师中编辑UI界面
(3)编辑控件的布局,调整界面控件的排列显示,包括水平、垂直、表格等布局方式,调整界面各控件位置、大小,修改属性、外观等,达到自己想要的效果。
3.添加响应函数
完成界面中的控件、布局、属性等编辑后,需要为控件添加信号的槽函数,以及具体代码。
(1)在UI设计界面中选中控件,选择右键菜单(指单击鼠标右键后弹出的菜单)中的“转到槽”选项,为控件添加信号的槽函数。在槽函数中编写具体的代码。
(2)各种控件有丰富的信号,控件有基类、基类的基类等,在通过“转到槽”选项打开的对话框中,可以看到很多信号,它们是控件、控件的基类提供的信号。
子类化是程序设计的一个重要的内容。这里的子类化是指基于Qt中已经存在的控件类,继承该类,将实现具体功能的代码实现在子类代码中,之后在界面的UI设计中将一个基类控件提升为子类化的类。
下面举例实现一个复杂的表格编辑功能,实现复杂的表格编辑、显示功能,如图3-7所示。
1.复杂表格功能
实现一个复杂的表格功能,可以子类化Qt的表格类QTableWidget,在子类中实现具体功能,在主界面UI设计中只需要拖放一个QTableWidget控件,将该控件提升为子类化的类,将大部分功能代码编写在子类中,这样主界面的代码会非常简洁、清晰。
在这个复杂的表格功能中,单元格的显示、编辑都与常见的表格不同。例如,有的单元格的编辑会弹出下拉框,有的单元格会有选择框,有的单元格会有背景色标黄、标红。实现这些功能必须子类化QTableWidget,既复用了QTableWidget的一些表格功能,又能写代码实现一些特殊的功能,这里还涉及了Qt的MVC机制。在本书第3部分“工程实践”中会详细介绍Qt的MVC机制,本节主要描述子类化。
图3-7 复杂的表格编辑、显示功能
下面以子类化表格控件QTableWidget为例,介绍在Qt Creator中的具体操作步骤。
(1)在Qt Creator中新建工程等步骤略。本书中未特殊说明时,都使用Qt Creator 3.6。
(2)创建工程后,选中Qt Creator界面左侧的工程名称节点,单击鼠标右键,在弹出的菜单中选择“添加新文件”选项,在弹出的对话框中单击“Choose”按钮,Qt Creator的“新建文件”对话框如图3-8所示。
图3-8 Qt Creator的“新建文件”对话框
(3)在弹出的如图3-9所示的“向导—添加类”对话框中,填入名称和子类名称,使类继承自Qt的表格控件QTableWidget。如果这个对话框中没有要子类化的Qt类,则可以选择QWidget,之后在生成的代码中手动修改继承类、头文件引用等。单击“下一步”按钮,Qt Creator就会生成这里子类化的类。
(4)生成得到子类化的类后,打开主界面UI文件的Qt设计师窗口,拖曳一个QTableWidget控件,单击鼠标左键选中该控件,单击鼠标右键弹出菜单,选择“提升为”菜单,打开如图3-10所示的“提升的窗口部件”对话框,在“提升的类名称”框中填入子类名称,在“头文件”框中填入相对路径,单击“添加”按钮,在上部“提升的类”框中会出现添加的类,选中一个,单击下方的“提升”按钮,关闭该对话框。之后,UI设计界面中的表格控件就是子类化的那个类。
图3-9 “向导—添加类”对话框
图3-10 “提升的窗口部件”对话框
(5)将控件提升为子类后,就可以在界面的源码文件中,以ui->xxxx来访问子类对象(xxxx换成对象名称),调用子类的方法、函数,等等。
2.自定义控件
也可将子类编译为自定义控件,之后在编辑UI界面时,在Qt Creator界面左侧的控件面板中可以看到自定义控件,可以拖放到自己的UI界面中。
Qt自定义控件技术是一种非常有用的技术,适用于代码复用、框架软件、协作开发等场合。后面会对Qt自定义控件开发进行详细描述。
下面介绍重要的类——QObject。Qt中的QObject类是绝大多数Qt类的基类,QObject使每个子类都是一个对象类,即“万物皆对象”。Qt中各种机制的实现(如信号槽机制、子类父类的动态转换、定时器、子对象查询遍历等)都依赖于QObject。
打开QObject的源码头文件,分析出下列QObject的主要内容。
(1)获取父对象,子对象查找、转换。
(2)信号槽机制的实现。
(3)动态属性机制的实现。
(4)事件机制的实现。
(5)定时器的启动、停止。
(6)类型的动态转换。
在Qt源码中定位到QObject源码,逐个阅读QObject的方法,这样可以帮助理解Qt的机制。在使用Qt的过程中,很多功能的实现(如定时器、对象转换、对象查找)都可以使用QObject的方法。
图形界面类的QWidget类是窗口显示的基本单元。Widget意为小部件,所有的界面类都派生自QWidget。它实现界面绘制、绘图、拖曳、鼠标响应等事件,提供坐标转换等丰富的方法,与界面操作相关、能够想到的人机交互需求,在QWidget中都有接口方法。
Qt官方在Qt5中推荐以QML方式开发图形界面,这视个人习惯而定,因为Qt5也支持以QWidget的方式开发,所以使用Qt5仍然可以采用QWidget方式。Qt4的程序升级至Qt5,修改少量代码就可以成功升级。
用熟QWidget等Qt类之后,会感觉到Qt库充分考虑了人机交互的操作特点,将人机交互特点抽象成各种类、接口方法,这些设计的类非常好用。这一点是非常值得学习的,在设计接口代码时,也应使其像Qt库一样易于使用。
通过查阅QWidget的头文件,归纳出QWidget的主要内容,列出以下条目解释QWidget的重要作用。
(1)定义了多种交互的事件:绘图、拖曳、定时器等。
(2)定义了显示相关的坐标转换,子窗口坐标与父窗口坐标互相转换。
(3)实现了界面大小、位置、属性、样式等显示相关功能。
(4)实现了窗口的基本属性和操作,如显示、隐藏、风格样式等功能。
(5)定义了父QWidget和子QWidget的查找、转换等方法。
QtTest是Qt中的单元测试库,与Qt库的兼容性非常好,可以模拟界面事件、数据驱动、鼠标点击、键盘输入等,非常利于界面代码的单元测试编写。
在Qt Creator中可先建立QtTest的单元测试工程,然后编译使用QtTest。
QtTest的主题包括数据驱动测试、模拟GUI事件、播放GUI事件等,具体参见Qt帮助文档中的QtTest部分。
参照一段QtTest的单元测试代码,其中定义了一个单元测试函数toUpper,用于测试QString的toUpper函数,判断能否正确转换大小写。测试代码中定义小写的hello字符串,之后调用QString的toUpper函数与大写的HELLO字符串比较,QVERIFY判断结果是否通过,编译运行后,在Qt Creator的输出窗口中可以看到执行结果。
可以看出单元测试代码很容易编写,只需要编写几行代码,就能使用QtTest执行单元测试。虽然各种单元测试的库基本上都是易于使用的,但在Qt中使用QtTest就足够了,没必要再使用其他单元测试库。
在一套应用软件的基础架构中,要指明是采用C/S(Client/Server,客户端/服务器)还是采用B/S(Browser/Server,浏览器/服务器)。现在流行使用B/S技术实现各种应用软件,而本书的测试系统框架是基于C++和Qt开发的C/S应用程序,可以使用流行的浏览器程序实现吗?后面的章节分析C/S和B/S的特点,对此进行讨论。
有些应用会采用混合编程,根据功能需求的特点,交叉使用B/S、C/S,交叉使用多个编程语言、技术。在本节后面对此有一些讨论。
B/S和C/S是基础架构,在实现一套软件系统时,首先要明确是使用B/S还是使用C/S。
B/S:各种在浏览器打开、操作的软件系统。使用者不需要复制任何程序文件、软件安装包,有浏览器即可使用,互联网中的各类Web应用都是B/S软件。
C/S:各种本地启动exe执行操作的软件系统,包括各种本地应用程序都是C/S。使用者需要复制安装包,安装后才能使用。
这些年,一直流行唱衰C/S应用,从B/S应用流行的最近一二十年更甚,甚至用B/S应用完全取代C/S本地应用程序。但这是不可能的,大量的电脑游戏、编译开发工具、工业软件等本地应用程序不可能被替代。
本地应用程序越来越少,但总还是有的。前几年流行远程操作系统,通过浏览器操作计算机,但直到今天,C/S应用仍然是非常重要的。
1.HTML5
一直以来,B/S应用很难替代本地应用的一些功能,显著的是绘图功能,直到HTML5的问世才出现了一些颠覆。HTML5中增加了大量特性,如绘图、流媒体,解决了传统浏览器应用不能实现的一系列功能,进而出现了大量Web应用颠覆传统软件的趋势。令人印象深刻的是,在HTML5刚出现时,有个网络版的照片处理软件,跟本地应用的PhotoShop软件基本一致。
技术不断向前发展,HTML5是一个里程碑。
2.浏览器中的JavaScript(DOM编程)
浏览器提供的开发接口有DOM(Document Object Model,文件对象模型)编程。由W3C国际万维网协会约定的浏览器标准要求所有浏览器都支持DOM。可以将DOM认为是浏览器提供给JavaScript的接口函数库。在所有的B/S前端页面中,都会调用DOM实现各种功能,DOM能访问、定义、修改浏览器界面的所有效果、多种功能。各类Web应用如此丰富,都是因为有DOM的支持。
Web应用是现在各类软件的主流,特别是在互联网火热的现今,有各种在浏览器中使用的Web应用程序。这些应用软件只要有浏览器、能上网就能使用。
1.特点
互联网上的Web应用是基于网页浏览器的软件系统,是一种典型的B/S系统,其最大特点是不需要安装任何程序,打开浏览器、输入网址就能够访问、使用,非常便捷。常见的Web应用如下。
(1)阿里云的远程桌面:在浏览器中运行的远程桌面、管理自己的云服务器,效果和Windows内置远程工具基本一致,很好用。
(2)在线绘图软件ProcessOn:支持在浏览器中多人同时绘图,实时性很好,可实现实时编辑、实时保存、多人实时协作编辑。
(3)在线UI设计软件Figma:功能丰富、强大,支持在浏览器中多人协同设计,实时性很好,可实现多人实时协作编辑。
常见的各类企业内部的办公自动化软件、审批软件、财务报销软件等,现在都基于浏览器模式。基于浏览器的免安装方式,使用非常方便。
这类应用的特点是:免安装、在浏览器中直接使用、有浏览器即可。
2.技术分析
Web应用等各类B/S软件都基于HTTP协议。在HTTP协议中,没有服务器主动向客户端发送数据,只能由客户端主动向服务器发送请求,服务器接收客户端的请求后,服务器才反馈数据给客户端。为了实时获取服务器的数据,只能定时用Ajax技术向服务器主动请求数据,达到一些实时效果。
因此在Web应用中,如果要实现两个浏览器间的交互,则需要设计一套服务器通信机制。在各个浏览器页面中设计一个定时器,Ajax定时向服务器请求数据,此时的实时性依赖于定时器的执行效率,可以近似实现假的实时性,在要求不高时可以这样使用。
3.Ajax
对于基于浏览器执行的各类应用软件,为了更新界面显示数据,经常需要使用者手动执行浏览器的刷新界面功能。为了避免反复执行刷新界面功能且没必要刷新整个界面,可使用异步的数据更新方式——Ajax。例如,在页面的JavaScript代码中加入定时器,定时通过Ajax向服务器请求数据,更新界面某个元素的显示,以此避免刷新整个界面,并能达到近乎实时刷新数据的效果。
Ajax(Asynchronous JavaScript and XML,异步JavaScript和XML)在2005年被提出,用来描述一种使用现有技术集合的“新”方法,包括HTML或XHTML、CSS、JavaScript、DOM、XML、XSLT,以及最重要的XMLHttpRequest。
使用Ajax技术,网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面,这使得程序能够更快地回应用户的操作。
可以认为B/S在技术层面的重要缺点是:无法实现真正的实时交互。因为很多应用也不需要真正的实时交互,所以B/S中的假实时交互也够用了。
4.分析
大量领域的系统都已基于B/S设计,这些领域也确实应该是免客户端模式,这是正确的。
5.B/S应用的缺陷——实时性差
B/S应用很多、很灵活、很好用。然而,这些应用不具备高实时性、本地硬件资源访问能力,这些功能是B/S系统实现不了的,这些功能也必须使用C/S程序、本地应用程序来实现。
实时性是很多软件系统的要求。在B/S应用程序中,浏览器的客户端程序受到HTTP协议本身的限制,没有服务器主动向客户端发送数据,所以不具备实时性。只能用异步请求(Ajax)定时向服务器请求数据,将定时器间隔时间改得很小,以模拟实时的数据显示、同步。针对这种实时性不强的问题,可以采用设计的方式进行改进。
(1)在服务器处理完大量数据后,直接把结果发送到客户端,此时只要服务器处理及时,就能够满足这种实时性需求,如流行的前、后台分离。
(2)界面数据更新频率是B/S系统实时性的主要表现形式。这时有影响的因素如下:网络环境怎么样、硬件性能怎么样、软件环境怎么样。改进这些因素可以提升B/S系统的实时性。
在B/S系统中实现实时性的功能,需要定义定时器,定时向服务器请求数据。此时,涉及定时器的周期,周期越短,实时性越高。但是,周期越短,越依赖于客户端的软、硬件环境,因此周期不能非常短。无法明确约定定时器的周期具体是多少,需要根据实际的需求自行确定。B/S系统中的定时器的周期最短单位是毫秒级,对于小于毫秒的实时性数据处理,B/S系统是无法完成的,必须用C/S程序实时处理。
6.B/S应用的缺陷——不能访问本地硬件资源
这是B/S应用的硬伤,浏览器中的程序不能访问本地硬件资源,最常见的是不能访问文件,网页中的JavaScript代码不能直接创建文件、直接访问文件,需要依赖HTML的文件控件才能进行有限的文件操作。
因此,在软件需要访问本地硬件资源时,浏览器的程序无法实现,必须使用本地应用程序,即便是编写浏览器插件提供服务,这个插件也算是本地应用程序。
绝大多数的企业信息应用都是基于网页版本的B/S应用,找不到C/S应用,只有一些和本地操作有关联的软件,如办公软件、三维软件、各种程序开发工具、浏览器、安全软件、设备控制类软件、数据采集类软件等。
1.本地应用软件
找几个需要客户端与服务器通信的程序,比较常见的如下。
(1)在线游戏软件,多人联机游戏,在线互动。
(2)即时通信软件,聊天软件QQ、微信、钉钉等,涉及文字、语音、视频的软件。
(3)远程协助软件,远程操作计算机、协助客户解决问题等。
2.程序库
在程序库方面,选择以下两个知名度高、重要性高的程序库。
(1)三维引擎OpenGL:几乎所有的虚拟现实游戏的基础都是OpenGL。OpenGL是绝大部分的三维显示的基础。OpenGL是用C++编写的程序库。也有一些编程语言封装了OpenGL,将接口封装提供给了其他编程语言,基础是OpenGL。
(2)脚本引擎Google V8:谷歌浏览器中实现DOM的核心组件是Google V8,Web应用的基础是浏览器,而有些浏览器的核心是基于Google V8实现的JavaScript脚本引擎。知名的Web服务端程序库Node.js以Google V8的高性能做支撑。
3.应用的特点
在线游戏软件的特点是:绚丽的界面、三维炫酷、多玩家实时互动,这需要软件后台实时通信、实时性高、运行效率高。
即时通信软件需要高实时性地传递语音、视频等,其后台数据量大、实时性高。
4.技术分析
本地应用可以访问本地资源,读取硬盘数据、访问音/视频设备、访问计算机总线等,这些都是B/S浏览器无法实现的,依赖这些本地资源的软件必然是C/S本地程序的领地。
实现这些功能需要调用操作系统、设备驱动库,这些都是本地程序才能实现的。
5.未来趋势
几个假设:如果浏览器能够支持访问本地资源、如果HTTP协议改进能够支持服务器主动通信、如果浏览器的JavaScript执行性能进一步提高、如果网络带宽无限大,那么计算机只需要一个浏览器。
这很难实现,因为涉及多个层面的问题,不只是涉及技术,还涉及浏览器的定位、HTTP协议的定位等。这些需要大量的组织、协会来思考、约定,进展会非常慢。
在看得见的未来若干年,浏览器应用和本地应用一定会并存下去,大量传统的本地应用软件会被Web应用替代。
6.测试系统中的B/S功能
最后答案:在测试系统中可以加入一些浏览器的B/S功能,用浏览器执行一些配置编辑、数据查询等没有实时性要求的功能,这些可以规划为测试信息化。本书的第4部分专门介绍测试信息化建设的内容。