我们可以写一些来使这个对话框有适当的功能。最干净利落的方式是创建一个新的继承自QDialog和Ui::GoToCellDialog的类,并实现缺少的功能(从而可以证明,简单的增加另一个间接的层来解决任何软件问题这个格言)。传统的命名方式是给这个类名是由uic生成的去掉Ui::前缀的类名。
使用文本编辑器,创建一个包含下列代码的gotocelldialog.h头文件:
在gotocelldialog.cpp中实现:
在构造函数中,我们调用setupUi()函数来初始化这个窗体。感谢多继承,我们可以直接访问Ui::GotoCellDialog的成员。在创建了用户界面后,setupUi()函数自动把所有的槽连接到相应的信号,槽的命名方式是on_objectName_signalName(),对应于对象名为objectName的signalName信号。在我们的例子中,这表示建立了如下的信号-槽连接:
在构造函数中,我们还建立了一个验证器来约束行编辑器的输入范围。Qt提供了3个内建的验证器类:QIntValidator, QDoubleValidator, 和QRegExpValidator.。这里我们使用了一个使用了正则表达式串"[A-Za-z][1-9][0-9]{0,2}"的QRegExpValidator,这表示允许一个大写或小写的字母,后面跟着一个1到9的数字,再跟着0到2个范围为1到9的数字。(要获得正则表达式的介绍,请看QRegExp的类文档。)
通过传递this指针到QRegExpValidator的构造函数,我们把验证器对象设为GoToCellDialog对象的一个子级。这样做我们就不用操心稍后验证器的delete的事儿;当它的父级被delete时它会自动被delete。
Qt的父子级机制在QObject中实现的。当我们创建一个带有父级的对象时(一个窗体,一个验证器,或其它种类的对象),父级把它的子级对象加到它的子级对象表中。当父级被delete时,它就会遍历它的子级对象表并删除每个子级对象。而各子级对象会delete掉各自的子级对象,直到当前遍历到的对象没有子级对象前一直递归下去。
这种父子级机制很大的简化了内存管理,减少了内存泄露的危险。我们必须唯一显示delete的对象是那些用new创建出来的没有父级的对象。如果我们在某个子级对象的父级对象delete掉它之前先delete掉它,则Qt会自动在父级对象的子级对象表中删除这个子级对象。
对于窗体来说,父级还有一个附加的意义:子级窗体显示在它的父级的区域中。当我们delete掉这个父级窗体时,不仅仅这个子级在内存中不复存在,也会在屏幕上消失。
在构造函数的最后,我们把OK按钮连接到accept()槽,把Cancel按钮连接到reject()槽。两个槽都会关掉对话框,但是accept()会设置对话框的结果值(result value)为QDialog::Accepted(等价于1),reject()会设置这个值为QDialog::Rejected(等价于0)。当我们使用这个对话框时,我们可以从这个结果值得知用户按下的是是否是OK按钮并执行相应的动作。
这样就完成的这个对话框。我们现在重写main.cpp来使用这个对话框:
重建这个程序(qmake -project;qmake gotocell.pro)并再次运行。在行编辑器中输入"A12",然后注意到OK按钮变成可用了。再键入一些随机的字符看看验证器如何工作的。点击Cancel按钮关掉这个对话框。
使用Qt设计师的一个好处就是允许程序员以更大的自由来修改他们的窗体的设计而不用强迫他们改变源代码。当你用纯C++来开发一个窗体,要做一些改动的话是很浪费时间。但有了Qt设计师,并不会浪费什么时间,因为uic会简单的重新生成窗体的源代码。这个对话框的用户界面存放在一个.ui的文件中(一种基于XML的文件格式)。而自定义功能是通过继承uic生成的类来实现的。