17.4 Qt构件
Qt中有针对各种用途的构件,如果全部讨论就会占用很大的篇幅。在本节中,你将看到一些常见的Qt构件,包括:数据输入构件、按钮、组合框和列表构件。
17.4.1 QLineEdit
QLineEdit是Qt的单行文本输入构件。你可以用它来输入简短的文本,如用户的名字。在使用该构件时,你可以使用一个输入掩码来限制输入以符合模板的要求,或者为了实现最终控制,你可以应用一个验证函数(例如,为了确保用户输入一个正确的日期、电话号码或其他类似的值)。QLineEdit具有编辑特性,它允许你从一个用户的角度或是使用API的角度来选择部分文本、剪切和粘贴、撤销、重做等。
它的构造函数和最有用的方法有:
在构造函数中,你像往常一样通过参数parent和name来设置父构件和构件名。
一个有趣的属性是EchoMode,它决定文本在构件中的显示方式。
它可以取下面3个值之一。
❑ QlineEdit::Normal:显示输入的字符(默认)。
❑ QlineEdit::Password:显示星号(用星号来取代字符)。
❑ QlineEdit::NoEcho:什么也不显示。
使用setEchoMode来设置模式:
Qt 3.2引入了一个增强特性inputMask,它按掩码规则来限制输入。
inputMask是一个由字符组成的字符串,其中每个字符都对应一个接受某个特定字符范围的规则。如果你熟悉正则表达式,inputMask使用的原理与其基本相同。
inputMask字符有两种类型:一类是表示某个特定字符必须出现,另一类指示如果某个字符出现,它需要受到规则的限制。表17-1显示了这些字符的示例和它们的含义。
表 17-1
inputMask是一个由这些字符组合在一起构成的字符串,有时以分号结束。还有几个具有特殊含义的字符,如表17-2所示。
表 17-2
inputMask中的所有其他字符在QLineEdit中都被视为分隔符。
表17-3显示了一些掩码示例和它们允许的输入。
表 17-3
实 验 QLineEdit
现在看一下QLineEdit的实际使用情况。
(1)首先是头文件LineEdit.h:
(2)LineEdit.cpp是我们很熟悉的类实现文件:
(3)用QGridLayout排列构件。指定行数、列数、边距和间隔:
运行这个程序,你将看到如图17-5所示的窗口。
图 17-5
实验解析
上述创建了两个QLineEdit构件,其中一个通过设置它的EchoMode将其变为密码输入框,当你点击PushButton按钮时,它的内容将被输出。注意,程序中引入了一个QGridLayout构件,当在网格模式下布置构件时,它非常有用。当你要把一个构件添加到网格中时,需要传递行号和列号。左上角的单元格是起始单元格,它的行列号分别是0,0。
17.4.2 Qt按钮
按钮构件是一种随处可见的构件,不同的工具包中它的外观、用法和API都变化不大。Qt当然也提供了标准的PushButton、CheckBox和RadioButton的变体。
1.QButton:按钮基类
Qt中的按钮构件都是派生自抽象类QButton。这个类有查询和切换按钮开关状态的方法,还有设置按钮文本或位图的方法。
你永远不需要实例化一个QButton构件自身(不要混淆QButton和QPushButton),所以这里也不用显示它的构造函数,但下面列出了它的几个有用的成员函数:
isDown和isOn函数的作用是相同的。它们都在按钮被按下或激活时返回TRUE。
通常,当某个选项当前不可用时,你希望能禁用它或让它显示为灰色。你可以通过调用Qwidget::setEnable(FALSE)来禁用包括QButton在内的任何构件。
下面是3个我们感兴趣的QButton子类。
❑ QPushButton:一个简单的按钮构件,它在被点击时执行一些动作。
❑ QCheckBox:一个可以在开/关(on/off)状态之间切换,用于表示某一选项的按钮构件。
❑ QRadioButton:通常在组中使用的按钮构件,一组内同时只能激活一个按钮。
2.QPushButton
QPushButton是一个标准的通用按钮,它包含如OK或Cancel这样的文本或一个像素映射图标。与所有的QButton一样,当它被激活时会发出一个clicked信号,这个信号通常会连接到一个槽并执行一些动作。
你已在前面的例子中用过QPushButton,关于这个最简单的Qt构件还有一件值得说的事:你可以调用setToggleButton将QPushButton从一个无状态按钮转变为一个开关按钮(即它可以被打开或关闭)。请回忆上一章的内容,GTK+用一个单独的构件实现此功能。
从完整性考虑,这里提供了它的构造函数和几个有用的方法:
3.QCheckBox
QCheckBox是一个有状态的按钮,也就是说,它可以被打开或关闭。它的外观取决于当前的窗口样式(Motif、Windows等),但它通常是一个右边有文本的打勾框。
你还可以将QCheckBox设置为第三种状态(即中间状态)以表示“无改变”。这在极少数情况下会用到,比如说你无法读取QCheckBox代表的选项的状态(因此,你自己设置QCheckBox的打开或关闭),但是仍然想给用户一个机会保持它状态的不变。
4.QRadioButton
单选按钮是开关按钮,它用于在一组选项中只能选择一个选项的情况(回想那些老式汽车的收音机,每次只有一个电台按钮可以被按下)。QRadioButton本身与QCheckBox几乎没有什么区别,这是因为按钮的分组和单选性都是由QButtonGroup类来处理的。它们之间主要的区别是,单选按钮的外观是圆的,而不是一个打勾框。
QButtonGroup是一个构件,它提供了一些便捷的方法,使得按钮组的处理更加容易:
QButtonGroup的用法非常简单,如果你使用带title参数的构造函数,它甚至还提供了一个可选的包围按钮的框架。
你有两种向QButtonGroup添加一个按钮的方法:一种是用insert方法,另一种是将QButtonGroup指定为按钮的父构件。你可以在调用insert时指定一个id来唯一标识组中的每个按钮。这在查询哪个按钮被选中时特别有用,因为selectId返回被选中按钮的id。
所有加到组内的QRadioButton都自动具有了单选性。
下面是QRadioButton的构造函数和唯一的方法:
实 验 QButton
让我们通过一个Qt按钮的示例程序来应用这些知识。下面这个程序通过创建不同类型的按钮(单选按钮、检查框和标准按钮)来显示如何在应用程序中使用这些构件。
(1)输入Buttons.h:
(2)稍后,你将在槽函数中查询按钮的状态,所以在类定义中将按钮指针声明为私有,还有一个辅助函数PrintActive也是私有的:
(3)下面是Buttons.cpp:
(4)你为两个单选按钮创建了一个QbuttonGroup:
(5)接下来是一个输出给定QButton状态的便捷方法:
实验解析
这个简单的例子显示了如何查询各种类型的Qt按钮。正如你所看到的,这些构件在创建后大多数情况下的工作方式基本相同。例如,PrintActive函数显示了如何获取一个按钮的状态(打开或关闭)。请注意,这个函数可以用于所有维持状态的按钮类型,如检查框和单选按钮。在大多数情况下,只有创建这些按钮构件的方法彼此不同。相对而言,单选按钮的创建过程是最复杂的(因为一个组中同时只能有一个按钮处于打开状态),它需要的工作量最大。对单选按钮来说,你需要先创建一个QButtonGroup,以确保组中在任何时候只能有一个单选按钮是激活的。
17.4.3 QComboBox
单选按钮适用于用户从少量选项(6个或更少)中进行选择的情况。当多于6个选项时,你就很难控制窗口的大小在一个合理的范围内,而且随着选项数目的增多,这一状况会越来越严重。一个完美的解决方案是使用一个带有下拉菜单的输入框,即组合框。当你点击菜单时选项才会出现,选项的数目只受到搜索选项列表方便程度的限制。
QComboBox结合了QLineEdit、QPushButton和下拉菜单的功能,它使用户可以从一个无限的选项中选择一个选项。
QComboBox可以是读/写或只读的。在读/写模式下,用户可以输入一个替代选项;而在只读模式下,用户只能从下拉菜单中进行选择。
在创建QComboBox时,你可以通过其构造函数的一个布尔值参数来指定它是读/写模式,还是只读模式:
传递TRUE将QComboBox设置为读/写模式。其他参数是常见的父构件指针和构件名。
与所有Qt构件一样,QComboBox的使用方式很灵活,而且它提供了大量的功能。你可以单个添加选项,也可以一次添加一组(使用QString或传统的char*格式)。
你可以调用insertItem来插入一个选项:
它有一个QString对象参数和一个位置索引参数。值1设置该选项为列表中的第一个选项。如果你想将它添加到列表的末尾,只需传递一个任意的负整数即可。
更常见的情况是一次添加多个选项,这时你可以使用QStrList类,或者像下面这样用一个char*数组:
同样,你也可以指定插入项在列表中的索引。
如果QComboBox是读/写模式,那么用户输入的值将自动加入到选项列表中。这是一个很有用的节省时间的功能,当用户想不止一次地选择同一个输入值时,它可以节省用户重复输入的时间。
InsertionPolicy控制新输入的值在选项列表的何处插入。你可以选择的选项见表17-4。
表 17-4
你可以调用setInsertionPolicy方法来设置QComboBox的插入策略:
下面看一下QComboBox的构造函数和部分方法:
count函数返回列表中选项的数目。QStringList和QStrList是你可以用来增加选项的Qt字符串集合类。你可以调用removeItem来删除选项,调用currentText和setCurrentText来获取和设置当前选项,调用setEditable来切换可编辑状态。
每当一个新选项被选中时,QComboBox就发出textChanged(QString&)信号,并以新选中的选项做为其参数。
实 验 QComboBox
在本例中,你将尝试使用QComboBox,并看到带参数的信号和槽是如何工作的。你将创建一个继承自QMainWindow的ComboBox类。它有两个QComboBox,一个是读/写模式,一个是只读模式,你将连接textChanged信号,以获取每次选中的值。
(1)输入下列代码,并将它命名为ComboBox.h:
(2)界面由两个QComboBox构件组成,一个可编辑,另一个是只读模式。你在两个构件中放置相同的选项列表:
(3)下面是槽函数。注意由信号传递的QString参数:
在图17-6中,你可以看到,可编辑的QComboBox里新选中的选项输出在命令行上。
图 17-6
实验解析
创建组合框构件的过程与创建任何其他构件的过程非常相似。它主要增加了一个对insertStrList函数的调用来存储组合框的选项列表。
和其他包含文本的构件一样,你可以设置一个函数,每当组合框中的值(或更通用的说法:文本)被改变时,该函数就会被调用。
17.4.4 QListView
Qt中的列表和树由QListView构件提供。QListView既可以显示平面列表,也可以显示被分为行和列的层次化数据。它非常适合于显示如目录结构这样的数据,因为子元素可以通过点击加减(+/-)框被展开和收起,就像一个文件查看器一样。
与GTK+的ListView构件不同,QListView同时处理数据和视图,虽然它没有提供很好的灵活性,但却提供了很好的易用性。
在使用QListView时,你可以选择行或单独的单元,然后剪切和粘贴数据、按列排序,而且你可以在单元里放置QCheckBox构件。QListView内建了很多功能,程序员只需添加数据和建立一些格式规则。
你按通常的方式创建QListView,指定父构件和构件名:
你可以使用addColumn方法来设置列标题:
列宽按像素设置,如果省略此参数,那么默认它为该列中最宽的元素的宽度。当列中元素增加或减少时,列会自动调整其宽度。
数据通过QListViewItem对象添加到QListView,它代表了一行数据。你所要做的就是把QListView和行元素传递给QListViewItem的构造函数,然后它就被附加到视图中:
第一个参数要么是一个QListView(本例即是如此),要么是另一个QListViewItem。如果你传递了一个QListViewItem,这一行会变成该QListViewItem的子节点。树形结构就是通过传递一个QListView作为顶层节点,后续传递的QListViewItem作为子节点而形成的。
其余参数是每列的数据,如果没有设置就默认为NULL。
这样,添加一个子节点只需要传递一个顶层指针。如果不想在将来继续在一个QListViewItem下添加子节点,你就不需要保存返回的指针:
如果看一下QListViewItem的API,你会看到用于遍历树的各种方法(如果你想要修改特定行的话):
你可以通过在QListView自身上调用firstChild来获取树中的第一行。然后,通过反复调用firstChild和nextSibling来返回这个树的一部分或全部。
下面这段代码输出所有顶层节点的第一列:
你可以在Qt API文档中找到关于QListView、QListViewItem和QCheckListView的所有细节。
实 验 QListView
在这个实验中,运用你所学的知识,编写一个短小的QListView构件示例程序。
为简洁起见,让我们跳过头文件,直接看类的实现文件ListView.cpp:
实验解析
QListView构件看上去很复杂,因为它同时扮演了项目列表和项目树的角色。你的代码需要为列表中的每个元素创建一个QListViewItem实例。每个QListViewItem实例都有一个父节点。使用构件本身作为其父节点的是顶层节点,使用另一个QListViewItem作为其父节点的是子节点。这个例子显示了一个只有一层深度的QListViewItem实例,但你实际上可以创建更深的节点树。
编译并运行这个ListView例子,你将看到如图17-7所示的QListView构件。
图 17-7
注意:子行是如何相对于父行缩进的。加/减框表明那里有隐藏或可折叠的行,它们在默认情况下不展现出来。你是通过setRootIsDecorated来设置它们的。