Qt教程-Qt Creator开发实例-计算器

经过前面的几篇文章,相信大家对于Qt Creator这个IDE以及Qt基本的使用方法有所了解。这篇文章我们使用已经了解过的技术简单的定制一个计算器。
这里我们基于Qt Creator中定制GUI程序04(国际化多语言)中提供的工程在继续往下开发。
相信大家都用过Windows下的计算器,作为一个计算器,我们需要一个用来输入和显示结果的文本框(QTextEdit),我们还需要一些数字符号的按钮(QPushButton)。这些都是常用的控件,我们可以直接在Qt Creator上拖出来。

我们这里对整个窗口使用垂直布局,最上方放置了一个文本框,下方我们放置了一个QGridLayout(珊格)布局在布局中放置了很多个按钮分别表示数字0-9和加减乘除等按钮。
放置后我们需要调整标识控件的名称(objectName属性),控件显示的内容(比如QPushButton中的text属性),控件自动缩放的属性(sizePolicy),并为每个按钮控件设置快捷键(shortcut属性)。
设置完成后结果如下图所示。

如果我们想对用户按下按钮作出反应,常规的做法是,为每个按钮注册Clicked的信号。不过很显然我们一个一个注册实在是太麻烦了,这里我们使用了一个偷懒的办法,按钮组(QButtonGroup)。如果我们需要处理界面上多个类似功能的按钮,我们可以把这些按钮组成一个组,然后为一个组设置一个响应函数就可以了。

在这里需要注意的是Qt Creator不能直接对buttonGroup组本身设置槽函数,所以需要手动创建一个槽函数并手动连接到信号。
这里我选择在界面初始化时connect buttonGroup的buttonClicked信号到一个MainWindow中的Button_clicked函数。

这样组内的任意按钮产生Clicked事件都会调用Button_clicked这个函数,我们可以看到Button_clicked函数传入了一个QAbstractButton对象的指针,这个指针用来确定组中具体是哪个按钮被按下了。
在计算器上,如果用户按下的按钮是数字,则显示在文本框里,如果是符号,则展开清屏或者计算操作。
这里我直接给出实现。

我们简单的解释一下,通过ojbect_button指针我们可以调用text函数获取控件的text属性,通过text属性我们就可以知道是哪一个按钮被按下,如果是数字则直接添加到textEdit文本框中,如果是符号则进行相关处理。通过setText函数我们可以设置文本框显示的内容。
这里为了避免未知的问题,我限制了表达式的长度为20个字符,超过会显示ERROR,大家可以自行修改此处。
我们可以看到当等号按钮被按下时,这里调用了calc_string_to_rpn_string和calc_rpn_string这两个函数。这两个函数用于把我们常见的中缀表达式转换成逆波兰表达式(也叫后缀表达式),最后在计算逆波兰表达式得到结果。
把中缀表达式转换成逆波兰式是为了更方便我们进行计算,这方面网络上有非常多的资料,我不过多赘述,直接给出有关的实现。

这里我们简单的说明一下,QString这个类与std::string有一些区别。我们都知道std::string实际上就像个vector是一个单字节的字符串实现,很显然char类型容纳不了所有的汉字,为了能储存显示汉字(或者其他的语言)std::string在不同平台可能有不同的编码实现,比如在Linux上std::string中的内容采用的是UTF-8编码,而在Windows下使用的则是ANSI编码,对于中文版的Windows来说就是GBK编码。如果全都是UTF-8可能没有什么问题,但是对不同语言版本的Windows编码就成为了大难题,如果开发者想一劳永逸的解决各个语言版本的编码兼容性,Microsoft推荐大家使用UNIOCDE编码(对于高于Windows 2000的系统版本,就是UTF-16编码,至于低于Windows 2000的系统版本,我建议选择拒绝兼容)但是使用UTF-16编码则不能直接与Linux系统兼容。
多系统的兼容很显然是一件非常麻烦的事情,作为传统的开发方法,开发者必须考虑每个平台的特点作出取舍或者写上一堆转换编码的函数互相转换。在Qt中QString这个类为我们提供了统一的解决方案,QString内部采用了UNIOCDE编码,这样使得任何文字都能正确的储存在QString中,在Windows上也可以直接获得良好的兼容性。当然作为牺牲,如果想用我们熟悉的char来解决问题,需要使用toLatin1函数转换成Latin1编码。
QStack和std::stack类似,用来作为栈这种数据结构使用,熟悉栈的同学应该对pop,push,top等操作一目了然。
最后我们可以编译看运行结果。运行结果如下图所示。

当用户按下等号后将会计算出正确结果14.
工程源代码下载地址:
https://www.exvs.org/wp-content/uploads/public/Qt_Tutorial/qt_calculator_FCE2BED0.7z

Qt教程-Qt Creator中定制GUI程序(界面布局)

绝大多数的GUI界面都是直接由各种控件组合堆叠而成的,有的程序界面设计的优良能从容面对各种状况(比如界面拉伸,多语言扩展),也有一些界面本身就不太友好(比如界面文字显示不全,控件不对齐),那么想设计一个友好的界面我们就必须得用到界面布局这样的功能。这里我们介绍一下Qt中界面布局的使用方法。
在Qt中进行界面布局有2种方法,第一种绝对定位,第二种布局定位。我们首先来看第一种。我们平常使用的界面大多都是长方形或者正方形,我们可以把界面想象成大棋盘,棋盘上的每一个点都有固定的坐标,我们把控件放到这些坐标点上就能堆叠出我们想要的样子。这样的布局方法就是绝对定位,控件在固定的位置不会变动。绝对定位很方便,把空间拖到想要放的地方就行了,但是很明显,如果窗体的大小做出了改变控件并不会因此做出任何响应,我们可能会因此看到界面上出现大片的留白。我们也可以通过设置窗体属性限制用户改变窗口的大小,但这并不一定是个好方法。当然我们也可以自己拦截窗口的消息事件通过自己的代码动态的确定各种控件的位置和大小,但是很显然,这样太麻烦了。
这种时候我们我们就在Qt中就可以使用布局定位的方法使得控件能够自动的拉伸各种控件或者改变控件的各种坐标。
我们先看一张示意图。

界面布局中通常是这样设计的,这里有几种布局器可以使用。
QHBoxLayout:按照水平方向从左到右布局。
QVBoxLayout:按照竖直方向从上到下布局。
QGridLayout:在一个网格中进行布局,类似于excel中单元格那样。
QFormLayout:按照表格布局,每一行前面是一段文本,文本后面跟随一个组件(通常是输入框)。
我们可以在窗口布局中嵌入其他的布局,最后形成我们看到的界面。
我们可以先创建自己的布局控件放入布局中做出自己想要的样子。这个时候可能运行起来还是不能自动缩放布局的,我们还得为窗口创建布局,并且得确保所有控件都处于可缩放的状态。
窗口创建布局:

此外所有需要缩放的控件都需要设置SizePolicy属性。这个属性来控制布局管理中的控件的尺寸自适应方式。
有下面几种属性可以选择。
Fixed:控件不能放大或者缩小,控件的大小就是它的sizeHint。
Minimum:控件的sizeHint为控件的最小尺寸。控件不能小于这个sizeHint,但是可以放大。
Maximum:控件的sizeHint为控件的最大尺寸,控件不能放大,但是可以缩小到它的最小的允许尺寸。
Expandint:控件可以自行增大或者缩小。
注:sizeHint(布局管理中的控件默认尺寸,如果控件不在布局管理中就为无效的值)

我们都选择为Expandint即可实现自适应窗口大小。
通过Qt Creator我们可以很方便的实现可视化的界面设计,当然如果有特别的需要也可以通过手工编写代码的方式来完成界面布局。
Qt文档中给出的例子如下:

该例中创建了5个Button控件,然后把控件都加入QHBoxLayout,最后形成的效果就是5个按钮按照顺序水平方向排列。

Qt教程-Qt Creator中定制GUI程序(国际化多语言)

作为一个设计良好的Qt程序,支持多国语言是显而易见的需求,毕竟需要照顾到的用户人群也许是不分国界的,那么如何使得程序拥有多语言则是一个很大的问题,这里我们继续使用之前的例子来演示多语言的处理。
要设计多语言,我们首先向工程中加入ts文件。
如下图所示:

也就是向pro文件加入

这里加入DISTFILES是给项目增加了其他文件的的意思,个人推荐加上这样方便点,当然也可以不加。
之后需要使用Qt Creator中的更新翻译菜单,更新翻译文件。
如下图所示:

这里注意.ts文件不要自己手工创建,如果创建了一个空文件再更新翻译,可能会收到类似这样的错误“zh_cn.ts:1:0: 文档过早的结束。”
更新完毕之后我们选择启动Qt语言家(Qt Linguist)对字符进行翻译。

启动Qt语言家后我们需要首先选择语言文件对应的是哪种语言。
如下图所示:

随后我们就能看到翻译界面,选择需要翻译的短语,然后填上相应的翻译内容最后保存即可。

这里注意的是,部分控件使用了html代码来控制格式内容,如果我们想保持和之前一致的显示风格,则需要连同html代码一起复制。这里我们为了演示效果,并没有留下html代码。
翻译完成后选择菜单的发布翻译即可,最后会生成一个qm文件。
为了让程序加载我们的翻译文件,我们需要在代码里面增加加载翻译的代码。
这里我们直接修改主函数,让程序根据系统设置的国家自动选择语言。

通过这些代码,如果系统设置为中国地区,程序在启动时会加载启动目录下的zh_cn.qm这个文件。这里需要注意的是,编译产生的可执行文件往往不在源代码目录,所以需要自行复制qm文件到可执行文件所在的目录。
最后运行效果如图

工程源代码下载地址:
https://www.exvs.org/wp-content/uploads/public/Qt_Tutorial/MainWindow_language_609C0483.7z

Qt教程-Qt Creator中定制GUI程序(添加多界面)

这一节我们将为之前创建的MainWindow工程添加第二个界面实现多窗口的演示。
首先打开之前的MainWindow工程,然后选择新建一个界面类,如下图所示:

之后我们可以选择一个Dialog界面模板,Dialog界面和之前创建的MainWindow有一点区别,默认是不会生成菜单栏,工具栏,状态栏这些的,一般Dialog界面用来做二级窗口。

选择以后我们继续下一步。

选择好类名,继续下一步。

最后完成创建。
之后我们打开aboutdialog.ui就可以对第二个界面进行设计了。

这里我们使用了QLabel控件,QLabel的功能就是显示文字或者图片,使用起来非常的简单。
接着我们回到mainwindow.ui的设计界面,为之前创建的关于菜单添加一个处理函数。

这里我们选择triggered信号,triggered信号和clicked有点像,不同的是clicked只能在被点击时触发,而triggered不仅可以被点击触发还可以被快捷键等方式触发。点击OK后Qt Creator会帮我们创建这么一个槽函数。
如下图所示:

我们写好槽函数之后,直接编译运行然后点击菜单后就可以看到效果。
那么问题来了,我们并没有看到connect函数把槽和信号连接起来,为什么最后却执行成功了呢?
我们可以看到moc处理完成的.h文件中最后调用了QMetaObject::connectSlotsByName函数,这个函数的作用就在于,这个函数通过特定的槽函数名,来自动连接信号和槽,这样我们就不需要再手工调用connect函数来连接了。
函数将自动连接符合on_object名字_信号名()这样名字的槽函数。举个例子,ui里面加一个按钮,按钮的object名字定位为 pushButton, 然后我们定义一个槽,叫 void on_pushButton_clicked();这样这个槽函数将会被自动连接。
最后我们编译运行后可以点击菜单查看效果,效果如下图所示。

Qt教程-导航目录(index)

基于Qt开发点什么并不是什么新鲜事,但是国内网络上大部分资料已经相对有些久远了,对于初学者来说这样的资料并不是很友好,所以我在这里想尝试重新编纂一份Qt的教程尽量的满足大家的需要。
算是给自己开个坑,也算强迫自己,希望这些文章对读者会有所帮助。由于文章众多,发布时间也不能完全按照顺序处理,故这里我新建一个导航目录。本系列文章我会按照推荐的阅读顺序在此罗列。

1、Qt介绍(暂无)
2、Qt开发环境安装与配置(暂无)
3、Hello World
4、信号槽
5、自定义信号槽和信号槽的实现
6、使用Qt Creator创建GUI程序
7、使用Qt Creator创建GUI程序02(添加图标,菜单,工具栏,状态栏)
8、Qt Creator中定制GUI程序03(添加多界面)
9、Qt Creator中定制GUI程序04(国际化多语言)
10、Qt Creator中定制GUI程序05(界面布局)
11、Qt Creator开发实例-计算器

未完待续
最后更新时间:2017/04/07