一、界面组件概述

在 Qt 类库中,所有界面组件类的直接或间接父类都是 QWidget。QWidget 的父类是 QObject 和 QPaintDevice,所以 QWidget 是多重继承的类。QObject 支持元对象系统,其信号与槽机制为 GUI 编程中对象间通信提供了极大的便利。QPaintDevice 是能使用 QPainter 类在绘图设备上绘图的类。所有从 QWidget 继承而来的界面组件被称为 widget 组件。

  • 按钮类组件。类继承关系如图所示,其中,QAbstractButton 是一个抽象类,它定义了按钮类的一些共有特性,但是不能用于创建实例对象:

示例图片

QCommandLinkButton 的功能类似于 QRadioButton,用于多个互斥项的选择,例如在向导对话框中作为一组互斥选择按钮。QDialogButtonBox 是一个复合组件类,可以设置为多个按钮的组合,例如包含 OK 和 Cancel 按钮,或 Yes、No 和 Cancel 按钮,可以放在对话框上,作为对话框的选择按钮。

  • 输入类组件。下图所示的是组件面板中 Input Widgets 分组的组件:

示例图片

输入类组件对应的类及其功能如表所示:

示例图片

  • 显示类组件。下图所示的是组件面板中 Display Widgets 分组的组件,显示类组件一般只能显示内容,而不能编辑、输入内容:

示例图片

Horizontal Line 和 Vertical Line 对应的类均是 QFrame,将 QFrame 类的 frameShape 属性设置为 HLine 或 VLine,并设置 frameShadow 属性为 Sunken,就具有了水平线条或垂直线条的效果,它们一般在界面上用作分隔线。界面类组件的功能如表所示:

示例图片

  • 容器类组件。在容器类组件上可以放置其他组件,并可以使用布局管理容器内的子组件。下图所示的是组件面板中 Containers 分组的组件:

示例图片

容器类组件对应的类及其功能如表所示:

示例图片

  • Item 组件。下图所示的是组件面板中 Item Views 和 Item Widgets 分组的组件:

示例图片

QAbstractItemView 的父类是 QAbstractScrollArea。Item Views 分组的组件用于模型/视图结构,每一种视图组件需要相应的一种模型用于存储数据。Item Widgets 组件类是相应 Item Views 组件类的子类,它们直接使用项(item)存储数据,称为相应视图类的便利类(convenience class),例如,QListWidget 是 QListView 的便利类,QTreeWidget 是 QTreeView 的便利类。

  • 其他界面组件。一些界面组件并没有出现在 Qt Designer 的组件面板里,例如常用的菜单栏(QMenuBar类)、菜单(QMenu 类)、工具栏(QToolBar 类)、状态栏(QStatusBar 类)等组件,对应的几个类都是直接从QWidget继承而来的。

QWidget 是所有界面组件类的基类,所以了解 QWidget 的基本特性,通常就能了解界面组件的通用特性。 在 Qt Designer 中设计界面时,QWidget 作为界面组件时的主要属性如表所示:

示例图片

组件的 sizePolicy 属性是QSizePolicy 类型,它定义了组件在水平和垂直方向的尺寸变化策略。下图展示了一个分组框中3个按钮水平布局在按钮的水平延展因子设置为不同值时的显示效果:

示例图片

在第一个分组框中,3个按钮的水平延展因子都是0,表示3个按钮的宽度平均。在第二个分组框中,前两个按钮的水平延展因子都是0,Button3 的水平延展因子是1,表示分组框宽度增大时,Button1 和 Button2 达到合适宽度后就不再增大,而 Button3 占据右边所有水平区域。在第三个分组框中,3 个按钮的水平延展因子分别是 1、1、2,相当于把总宽度分成四等份,Button3 的宽度是 Button1 的2倍。

QWidget 也可以作为独立的窗口,其子类 QMainWindow、QDialog 也是常用的窗口类。QWidget 作为窗口时有一些与窗口相关的属性,具体如表所示:

示例图片

当 QWidget 作为独立的窗口时,有如下一些与窗口显示有关的公有槽函数:

bool  close()           // 关闭窗口 
void  hide()            // 隐藏窗口 
void  show()            // 显示窗口 
void  showFullScreen()  // 以全屏方式显示窗口 
void  showMaximized()   // 窗口最大化 
void  showMinimized()   // 窗口最小化 
void  showNormal()      // 全屏、最大化或最小化操作之后,恢复正常大小显示 

QWidget 中定义的信号只有3个,定义如下:

void  customContextMenuRequested(const QPoint &pos) 
void  windowIconChanged(const QIcon &icon) 
void  windowTitleChanged(const QString &title)

其中,customContextMenuRequested() 信号是在组件上点击鼠标右键时被发射的,一般用于创建组件的快捷菜单。

二、布局管理

布局管理类的继承关系如图所示:

示例图片

QSpacerItem 从 QLayoutItem 继承而来,可以用于在布局中占位,或填充剩余空间。分割条组件类 QSplitter 是从 QWidget 继承而来的,所以它是一个可见的界面组件。

任何布局类对象在可视化设计时都有 layoutLeftMargin、layoutTopMargin、layoutRightMargin 和 layoutBottomMargin 这 4 个边距属性,这 4 个边距属性用于设置布局组件与父容器的4个边距的最小值,单位是像素。水平布局和垂直布局还有一个属性 layoutSpacing,表示组件的最小间距。 构建项目时,窗口 UI 文件被 MOC 预编译后生成一个头文件,例如 mainwindow.ui 对应的 MOC 预编译结果文件是 ui_mainwindow.h。在 MOC 预编译结果文件的函数 setupUi() 中会发现如下的代码:

groupBox = new QGroupBox(MainWindow);                 // 创建 groupBox,将窗口作为父容器 
groupBox->setGeometry(QRect(260, 310, 341, 43)); 
horizontalLayout = new QHBoxLayout(groupBox);         // 在 groupBox 里创建水平布局 
horizontalLayout->setSpacing(10);                     // 设置 layoutSpacing 
horizontalLayout->setContentsMargins(5, 5, 5, 5);     // 设置 4 个边距属性的值 
pushButton = new QPushButton(groupBox); 
horizontalLayout->addWidget(pushButton); 
pushButton_2 = new QPushButton(groupBox); 
horizontalLayout->addWidget(pushButton_2); 
pushButton_3 = new QPushButton(groupBox); 
horizontalLayout->addWidget(pushButton_3);

水平布局还有一个 layoutStretch 属性,表示3个按钮的延展因子,可以灵活控制各组件的宽度占比。对于水平布局 layoutStretch 属性实现的效果,还可以通过设置单个组件的 sizePolicy 属性中的 Horizontal Stretch 来实现。

网格布局是划分为行和列的,函数setupUi()中的实现代码如下:

groupBox = new QGroupBox(MainWindow);              // 创建 groupBox,将窗口作为父容器 
groupBox->setGeometry(QRect(290, 160, 200, 230)); 
gridLayout = new QGridLayout(groupBox);            // 创建网格布局,将groupBox作为父容器 
gridLayout->setHorizontalSpacing(7); 
gridLayout->setVerticalSpacing(12); 
gridLayout->setContentsMargins(10, 10, -1, -1); 
pushButton = new QPushButton(groupBox); 
gridLayout->addWidget(pushButton, 0, 0, 1, 1);     // 添加左上角的按钮 
pushButton_2 = new QPushButton(groupBox); 
gridLayout->addWidget(pushButton_2, 0, 1, 1, 1); 
comboBox = new QComboBox(groupBox); 
comboBox->addItem(QString()); 
gridLayout->addWidget(comboBox, 1, 0, 1, 2);       // 添加下拉列表框 
plainTextEdit = new QPlainTextEdit(groupBox); 
gridLayout->addWidget(plainTextEdit, 2, 0, 1, 2); 

QGridLayout 类添加组件的函数是 addWidget(),其函数原型定义如下:

/*
widget:     需要添加到布局中的组件
fromRow:    行号
fromColumn: 列号
rowSpan:    占用的行数
columnSpan: 占用的列数
alignment:  表示默认的对齐方式
*/
void  QGridLayout::addWidget(QWidget *widget, int fromRow, int fromColumn, int rowSpan, 
                      int columnSpan, Qt::Alignment alignment = Qt::Alignment()) 

实现分割条功能的类是 QSplitter,分割条可以实现水平分割或垂直分割,一般是在两个可以自由改变大小的组件之间进行分割:

splitter = new QSplitter(Form);                     // 创建 splitter,窗口对象是Form 
splitter->setOrientation(Qt::Horizontal); 
splitter->setOpaqueResize(true); 
splitter->setHandleWidth(8); 
splitter->setChildrenCollapsible(true); 
groupBox = new QGroupBox(splitter); 
groupBox->setMinimumSize(QSize(150, 0));            // 设置最小宽度 
splitter->addWidget(groupBox);                      // 添加到分割布局中 
plainTextEdit = new QPlainTextEdit(splitter); 
splitter->addWidget(plainTextEdit);                 // 添加到分割布局中

由代码可见,创建分割布局就是将分割条对象 splitter 作为两个组件 groupBox 和 plainTextEdit 的父容器组件。代码执行效果如下:

示例图片

三、QString 字符串操作

QString 没有父类,用于存储字符串,每个字符是一个 QChar 类型的数据。QChar 使用的是 UTF-16 编码,一个字符包含2字节数据。对于超过65535的 Unicode 编码,QString 使用两个连续的 QChar 字符表示。UTF-16 是一种 Unicode 编码,能表示汉字,在 QString 字符串中一个汉字是一个字符。

QString str = "dimple,酒窝"; 
QChar ch0 = str[0];     // ch0='d' 
QChar ch7 = str.at(7);  // ch7='酒'

QChar 定义了很多接口函数用于字符操作,QChar 类的主要接口函数如表所示:

示例图片

QChar 的函数 toLatin1() 用于将 QChar 字符转换为 Latin1 字符,也就是将 UTF-16 编码的字符转换为1字节 Latin1 编码的字符。

Latin1 字符集是对 ASCII 字符集的扩展,也是用1字节编码,它用128~255表示拉丁字母表中特殊语言字符的编码。

QChar 的接口函数 unicode() 用于返回字符的 UTF-16 编码,也就是 char16_t 类型的数。也可以通过 char16_t 类型的编码构造 QChar 字符,静态函数 QChar::fromUcs2() 可以实现这样的功能:

QChar QChar::fromUcs2(char16_t c)

QChar 有一个构造函数与这个静态函数功能相同,这个构造函数定义如下:

QChar::QChar(char16_t ch)

例如,运行下面的一段代码后,字符串 str 的内容由 “Hello,北京” 变为了 “Hello,青岛”:

QString str = "Hello,北京"; 
str[6] = QChar(0x9752);            // '青',使用构造函数
str[7] = QChar::fromUcs2(0x5C9B);  // '岛',使用静态函数

QString 定义了很多用于字符串操作的接口函数,如 append() 用于在当前字符串的后面添加字符串,prepend() 用于在当前字符串的前面添加字符串,toInt() 用于将字符串转换为整数等,对于其他的函数可查看 Qt 帮助文档。

四、QSpinBox 和 QDoubleSpinBox

QSpinBox 和 QDoubleSpinBox 是常用的数值输入和输出组件,将它们统称为SpinBox。QSpinBox 用于输入和输出整数,一般显示为十进制数,也可以按其他进制显示,而且可以设置显示的前缀和后缀。QDoubleSpinBox 用于显示和输入浮点数,可以设置显示的小数位数,也可以设置显示的前缀和后缀。QSpinBox 和 QDoubleSpinBox 都是 QAbstractSpinBox 的子类,具有很多相同的属性:

示例图片

QSpinBox 有两个特有的信号,信号定义如下:

// 在 value 属性值变化时被发射,传递的参数i是变化之后的数值
void  QSpinBox::valueChanged(int i) 
// 在显示的文字发生变化时被发射
void  QSpinBox::textChanged(const QString &text) 

SpinBox 组件 UI 示例界面:

示例图片

五、常用的按钮组件

常用的4种按钮组件是普通按钮(QPushButton类)、工具按钮(QToolButton 类)、单选按钮(QRadioButton类)、复选框(QCheckBox类),它们都有共同的父类 QAbstractButton。QAbstractButton 类的主要属性如表所示:

示例图片

六、QSlider 和 QProgressBar

滑动条(QSlider类)、卷滚条(QScrollBar类)和表盘(QDial类)3个类具有同一个父类 QAbstractSlider。进度条(QProgressBar 类)是用于显示数值的组件,特别适用于显示百分比进度。

示例图片

QAbstractSlider 是 QSlider、QScrollBar 和 QDial 的父类,它定义了这几个类共有的一些属性:

示例图片

QAbstractSlider 定义了几个信号,信号函数定义如下,信号触发时机见注释:

void  actionTriggered(int action)                 // 滑动条触发一些动作时 
void  rangeChanged(int min, int max)              // minimum 或 maximum 属性值发生变化时 
void  sliderMoved(int value)                      // 用户按住鼠标拖动滑块时 
void  sliderPressed()                             // 在滑块上按下鼠标时 
void  sliderReleased()                            // 在滑块上释放鼠标时 
void  valueChanged(int value)                     // value 属性值变化时

七、日期时间数据

Qt 定义了3个类用于表示和处理日期时间数据:QTime(表示时间数据的类,时间数据如12:04:35)、 QDate(表示日期数据的类,日期数据如2021-9-15)、QDateTime(表示日期时间数据的类,日期时间数据如2021-09-16 17:22:43)。Qt 定义了几个用于日期时间数据处理的界面组件类:

  • QTimeEdit:编辑和显示时间的组件类。
  • QDateEdit:编辑和显示日期的组件类。
  • QDateTimeEdit:编辑和显示日期时间的组件类。
  • QCalendarWidget:一个用日历形式显示和选择日期的组件类。

QTime类的主要接口函数:

示例图片

QDate类的主要接口函数:

示例图片

QDateTime 类的主要接口函数:

示例图片

八、QTimer 和 QElapsedTimer

QTimer 是软件定时器,其父类是 QObject。QTimer 的主要功能是设置以毫秒为单位的定时周期,然后进行连续定时或单次定时。QElapsedTimer 用于快速计算两个事件的间隔时间,是软件计时器。QElapsedTimer 没有父类,其计时精度可以达到纳秒级。QElapsedTimer 的主要用途是比较精确地确定一段程序运行的时长。

九、QComboBox

QComboBox 是下拉列表框组件,它可以提供下拉列表供用户选择输入,也可以提供编辑框用于输入文字,所以 QComboBox 也被称为组合框。QComboBox 类的主要属性如表所示:

示例图片

十、QMainWindow 和 QAction

QMainWindow 是主窗口类,具有菜单栏、工具栏、状态栏等主窗口常见的界面元素。要设计主窗口上的菜单栏、工具栏、按钮的下拉菜单、组件的快捷菜单等,需要用到 QAction 类。QAction 对象就是实现某个功能的“动作”,我们称其为 Action。

工具栏对应的是 QToolBar 类,QToolBar提供了接口函数,可以通过代码在工具栏上添加组件,从而灵活地设计工具栏,常用的几个函数定义如下:

void  addAction(QAction *action)     // 添加一个Action,并根据Action的设置自动创建工具按钮 
QAction  *addWidget(QWidget *widget)                          // 添加一个界面组件 
QAction  *insertWidget(QAction *before, QWidget *widget)      // 插入一个界面组件 
QAction  *addSeparator()                                      // 添加一个分隔条 
QAction  *insertSeparator(QAction *before)                    // 插入一个分隔条 

主窗口上的状态栏对应的是 QStatusBar 类,有两个函数用于添加组件,其函数原型定义如下:

void  addWidget(QWidget *widget, int stretch = 0)             // 添加正常组件 
void  addPermanentWidget(QWidget *widget, int stretch = 0)    // 添加永久组件 

十一、QListWidget

QListWidget 组件的列表项是 QListWidgetItem 对象,主要的接口函数如表所示:

示例图片

QListWidget 类的主要接口函数如表所示:

示例图片

QListWidget 组件中的每一行是一个 QListWidgetItem 对象,要在列表中添加或插入一个项,一般是先创建一个 QListWidgetItem 对象,设置其文字、图标等特性,然后用函数 addItem() 或 insertItem() 将该对象加入列表。

示例图片

十二、QTreeWidget

QTreeWidget 是一种 Item Widget 组件。QTreeWidget 组件被称为树形组件,它的项(item)被称为节点,一个树形组件内
的所有节点组成的结构称为目录树。

示例图片

工作区左侧是一个 QDockWidget 组件(停靠组件),对象名称是 dockWidget。在 dockWidget 上放置一个 QTreeWidget 组件,对象名称是 treeWidget,用水平布局使 treeWidget 填充满停靠区。工作区右侧是一个 QScrollArea 组件,对象名称是 scrollArea。scrollArea 里放置一个 QLabel 组件,对象名称是 labPic,可以利用 QLabel 的 pixmap 属性来显示图片。在窗口类 MainWindow 的构造函数里将 scrollArea 设置为主窗口工作区的中心组件后,dockWidget 与 scrollArea 之间会自动出现分割条。

一个 QTreeWidget 组件的显示内容分为表头和目录树两部分,表头和目录树节点都是 QTreeWidgetItem 对象。

  • 表头。树形组件有表头,表头可以只是简单的文字,也可以设置为 QTreeWidgetItem 对象。
  • 顶层节点。目录树里一行就是一个节点,节点是 QTreeWidgetItem 对象。节点可以有子节点,子节点就是下一级的节点,子节点可以继续有其子节点,可以层层嵌套。获取一个顶层节点对象后,就可以访问它的所有子节点。
  • 次级节点。所有次级节点都直接或间接挂靠在某个顶层节点下面,顶层节点和次级节点都是 QTreeWidgetItem 类对象。一个节点可以访问它的所有直接子节点,可以通过递归的方法遍历其所有直接和间接子节点。所以,从顶层节点开始,就可以遍历整个目录树。
  • 隐藏的根节点。目录树中还有一个隐藏的根节点,其可以看作所有顶层节点的父节点。函数 invisibleRootItem() 可以返回这个隐藏的根节点。使用这个隐藏的根节点,就可以通过 QTreeWidgetItem 类的接口函数访问所有顶层节点,这样在实现一些对顶层节点和次级节点进行操作的函数时,可以使用相同的程序。

QTreeWidget 还有如下一些常用的接口函数:

int  columnCount()                                          // 返回表头列数 
void setColumnCount(int columns)                            // 设置表头列数 
void sortItems(int column, Qt::SortOrder order)             // 将目录树按照某一列排序 
int  sortColumn()                                           // 返回用于排序的列的序号 
QTreeWidgetItem  *currentItem()                             // 返回当前节点 
QList<QTreeWidgetItem *>  selectedItems()                   // 返回选择的节点的列表

对目录树节点的操作主要通过 QTreeWidgetItem 类的接口函数实现。QTreeWidgetItem 类没有父类,它只用来存储节点的数据和各种属性,绘制目录树由 QTreeWidget 实现。

十三、QTableWidget

QTableWidget 是一种 Item Widget 组件,它以表格形式显示和管理数据,我们称为表格组件。

示例图片

表格组件数据区的每个单元格可以关联一个 QTableWidgetItem 对象,表头的单元格也是 QTableWidgetItem 对象。可以设置每个 QTableWidgetItem 对象的文字、字体、背景色、图标等特性。要为表格的一个单元格设置项,一般是先创建一个 QTableWidgetItem对象item,设置其各种属性,然后用函数 setItem() 将 item 设置为某个单元格的项,其函数原型定义如下:

void  setItem(int row, int column, QTableWidgetItem *item)
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐