在上一小节学习过视图组,下面学习控件组。仔细观察视图组里的某几个控件与控件组的控件名字相似。以 QListWidget 为例QListWidget 就是继承 QListView。QListView 是基于模型的,而 QListWidget 是基于项的。两种控件在不同的场合可以酌情选择使用!一般处理大数据使用基于模型的多。视图组与控件组的控件在 Qt 里展示数据时是会经常使用的!大家要掌握它们的使用方法。
以上各个控件的解释如下:
(1) List Widget:清单控件
(2) TreeWidget:树形控件
(3) Table Widget:表控件
以下是各个控件的简介:
QListWidget 继承 QListView。QListWidget 类提供了一个基于项的列表小部件。QListWidget 是一个便捷的类,它提供了一个类似于 QListView(下一小节将讲到)提供的列表视图,但是提供了一个用于添加和删除项目的基于项目的经典接口。QListWidget 使用内部模型来管理列表中的每个 QListWidgetItem。QListView 是基于 model 的,需要自己来建模(例如建立 QStringListModel、QSqlTableModel 等),保存数据,这样就大大降低了数据冗余,提高了程序的效率,
但是需要我们对数据建模有一定了解,而 QListWidget 是一个升级版本的 QListView,它已经自己为我们建立了一个数据存储模型(QListWidgetItem),操作方便,直接调用 addItem 即可添加项目(ICON,文字)。
QTreeWidget 继承 QTreeView。QTreeWidget 类提供了一个使用预定义树模型的树视图。QTreeWidget 类是一个便捷的类,它提供了一个标准的树小部件,具有一个类似于 qt3 中的 QListView 类所使用的基于项目的经典接口。该类基于 Qt 的模型/视图体系结构,并使用默认模型来保存项,每个项都是 QTreeWidgetItem。
QTableWidget 继承 QTableView。QTableWidget 类提供了一个带有默认模型的基于项的表视图。表小部件为应用程序提供标准的表显示工具。QTableWidget 中的项由 QTableWidgetItem 提供。
QListWidget 继承 QListView。QListWidget 类提供了一个基于项的列表小部件。QListWidget 是一个便捷的类,它提供了一个类似于 QListView(下一小节将讲到)提供的列表视图,但是提供了一个用于添加和删除项目的基于项目的经典接口。QListWidget 使用内部模型来管理列表中的每个 QListWidgetItem。
例 45_qlistwidget,添加“歌曲”(难度:简单)。本例使用一个 QListWidget 以及一个按钮,当单击按钮时,就会调用系统打开文件窗口,过滤 mp3 后缀的文件(本例使用 touch 指令创建2 个 mp3 后缀的文件,并不是真正的歌曲,在终端输入指令为 touch 0.mp3 1.mp3,本例在项目下已经创建了两个以 mp3 为后缀的文件),当打开系统文件选择框时,就会选择这两个 mp3 文件作为 QListWidget 的项添加到 QListWidget 的窗口中。(PS:我们写音乐播放器就要用到这种操作—打开歌曲。实际本例就是一个打开歌曲的代码部分。)
在新建例程中不要勾选“Generate form”,默认继承 QMainWindow 类即可。项目新建完成,如下图。
在头文件“mainwindow.h”具体代码如下。
1 #ifndef MAINWINDOW_H
2 #define MAINWINDOW_H
3
4 #include <QMainWindow>
5 #include <QListWidget>
6 #include <QPushButton>
7
8 class MainWindow : public QMainWindow
9 {
10 Q_OBJECT
11
12 public:
13 MainWindow(QWidget *parent = nullptr);
14 ~MainWindow();
15
16 private:
17 /* 声明对象 */
18 QListWidget *listWidget;
19 QPushButton *pushButton;
20
21 private slots:
22 void pushButtonClicked();
23
24 };
25 #endif // MAINWINDOW_H
在源文件“mainwindow.cpp”具体代码如下。
1 #include "mainwindow.h"
2 #include "QFileDialog"
3
4 MainWindow::MainWindow(QWidget *parent)
5 : QMainWindow(parent)
6 {
7 /* 设置主窗口的显示位置与大小 */
8 this->setGeometry(0, 0, 800, 480);
9
10 listWidget = new QListWidget(this);
11
12 /* 设置 listWidget 的大小 */
13 listWidget->setGeometry(0, 0, 480, 480);
14
15 listWidget->addItem("请单击右边的添加项添加内容");
16
17 pushButton = new QPushButton(this);
18
19 /* 设置 pushButton 的位置与大小 */
20 pushButton->setGeometry(540, 200, 200, 100);
21 pushButton->setText("添加项");
22
23 /* 信号与槽连接 */
24 connect(pushButton, SIGNAL(clicked()),
25 this, SLOT(pushButtonClicked()));
26 }
27
28 void MainWindow::pushButtonClicked()
29 {
30 /* 调用系统打开文件窗口,设置窗口标题为“打开文件”,过滤文件名 */
31 QString fileName = QFileDialog::getOpenFileName(
32 this,tr("添加项"),"",
33 tr("Files(*.mp3)")
34 );
35
36 /* 判断是否选中打开 mp3 文件 */
37 if (fileName != NULL)
38 /* 添加项到列表中 */
39 listWidget->addItem(fileName);
40 }
41
42 MainWindow::~MainWindow()
43 {
44 }
在源文件“main.cpp”具体代码由新建项目时生成,无改动。
程序编译运行的结果如下。当点击添加项按钮时出现系统选择文件的对话框,系统打开文件时会过滤 mp3 后缀的文件,点击后缀为 mp3的文件,双击或者选择后再点击右上角的“Open”的打开来把这个文件添加到左边的 QListWidget 列表中。读者可以模仿这个示例,还可以添加删除项的按钮,或者删除全部按钮等,酷狗音乐播放器的的歌单与此类似。后续继续学习如何播放音乐,与此结合,就可以做出一款音乐播放器了。
QTreeWidget 继承 QTreeView。QTreeWidget 类提供了一个使用预定义树模型的树视图。QTreeWidget 类是一个便捷的类,它提供了一个标准的树小部件,具有一个类似于 qt3 中的 QListView 类所使用的基于项目的经典接口。该类基于 Qt 的模型/视图体系结构,并使用默认模型来保存项,每个项都是 QTreeWidgetItem。
例 46_qtreewidget,群发信息(难度:一般),本例使用一个 TreeWidget,模拟成一个飞信联系人分组,通过选中组内联系人来“群发”信息。实际并不是真正做一个群发信息的飞信,只是模拟飞信群发信息时选择联系人的场景,通过例子来熟悉 QTreeWidget 的使用。本例相对前面的例子稍长,出现了树节点与子节点的概念。本例的思路:当选中顶层的树形节点时,子节点全部被选中;当取消选择顶层树形节点时,子节点原来选中的状态将全部取消;当不完全选中子节点时,树节点显示为半选状态。
在新建例程中不要勾选“Generate form”,默认继承 QMainWindow 类即可。项目新建完成,如下图。
在头文件“mainwindow.h”具体代码如下。
1 #ifndef MAINWINDOW_H
2 #define MAINWINDOW_H
3
4 #include <QMainWindow>
5 #include <QTreeWidget>
6 #include <QTreeWidgetItem>
7
8 class MainWindow : public QMainWindow
9 {
10 Q_OBJECT
11
12 public:
13 MainWindow(QWidget *parent = nullptr);
14 ~MainWindow();
15
16 private:
17 /* QTreeWidget 对象 */
18 QTreeWidget *treeWidget;
19 /* 顶层树节点 */
20 QTreeWidgetItem *parentItem;
21 /* 声明三个子节点 */
22 QTreeWidgetItem *subItem[3];
23
24 /* 子节点处理函数 */
25 void updateParentItem(QTreeWidgetItem*);
26
27 private slots:
28 /* 槽函数 */
29 void treeItemChanged(QTreeWidgetItem*, int);
30
31 };
32 #endif // MAINWINDOW_H
在源文件“mainwindow.cpp”具体代码如下。
1 #include "mainwindow.h"
2
3 MainWindow::MainWindow(QWidget *parent)
4 : QMainWindow(parent)
5 {
6 /* 设置主窗体大小 */
7 this->setGeometry(0, 0, 800, 480);
8
9 /* 实例化 */
10 treeWidget = new QTreeWidget(this);
11
12 /* 居中 */
13 setCentralWidget(treeWidget);
14
15 /* 清空列表 */
16 treeWidget->clear();
17
18 /* 实例化顶层树节点 */
19 parentItem = new QTreeWidgetItem(treeWidget);
20 parentItem->setText(0, "同事");
21
22 parentItem->setFlags(
23 Qt::ItemIsUserCheckable
24 | Qt::ItemIsEnabled
25 | Qt::ItemIsSelectable
26 );
27 /* 树节点设置为未选中 */
28 parentItem->setCheckState(0, Qt::Unchecked);
29
30 /* 字符串链表 */
31 QList <QString> strList;
32 strList<<"关羽"<<"刘备"<<"张飞";
33
34 for (int i = 0; i < 3; i++){
35 /* 实例化子节点 */
36 subItem[i] = new QTreeWidgetItem(parentItem);
37 /* 设置子节点的文本,参数 0 代表第 0 列 */
38 subItem[i]->setText(0, strList[i]);
39 /* 设置子节点的属性为用户可选、项开启、项可选 */
40 subItem[i]->setFlags(
41 Qt::ItemIsUserCheckable
42 | Qt::ItemIsEnabled
43 | Qt::ItemIsSelectable
44 );
45 /* 设置子节点的状态为未选中 */
46 subItem[i]->setCheckState(0,Qt::Unchecked);
47 }
48 /* 信号槽连接 */
49 connect(treeWidget,SIGNAL(itemChanged(QTreeWidgetItem* , int)),
50 this, SLOT(treeItemChanged(QTreeWidgetItem* , int)));
51
52 }
53
54 /* 更新树节点函数 */
55 void MainWindow::updateParentItem(QTreeWidgetItem *item)
56 {
57 /* 获取子节点的父节点(树节点) */
58 QTreeWidgetItem* parent = item->parent();
59 if(parent == NULL){
60 return;
61 }
62 /* 初始化选中的数目为 0,下面根据 selectCount 来判断树节点的状态 */
63 int selectCount = 0;
64 /* 获取树节点的子节点总数 */
65 int childCount = parent->childCount();
66 /* 循环判断子节点的状态 */
67 for(int i = 0; i < childCount; i ++){
68 QTreeWidgetItem* childItem =parent->child(i);
69 /* 判断当前子节点的状是否为选中状态,如果是,则加一 */
70 if(childItem->checkState(0) == Qt::Checked) {
71 selectCount ++;
72 }
73 }
74 /* 根据 selectCount 来判断树节点的状态 */
75 /* 当选中的子节点小于或等于 0 时,则为设置树节点为未选中状态 */
76 if (selectCount <= 0) {
77 /* 设置树节点为未选中状态 */
78 parent->setCheckState(0, Qt::Unchecked);
79 /* 部分选中时,树节点为半选状态 */
80 } else if (selectCount > 0 && selectCount < childCount) {
81 /* 设置为半选状态 */
82 parent->setCheckState(0, Qt::PartiallyChecked);
83 /* 子节点全选时 */
84 } else if (selectCount == childCount){
85 /* 设置为树节点为选中状态 */
86 parent->setCheckState(0, Qt::Checked);
87 }
88 }
89
90 void MainWindow::treeItemChanged(QTreeWidgetItem *item, int)
91 {
92 /* 获取子节点总数 */
93 int count = item->childCount();
94
95 /* 若顶层树节点选中 */
96 if(Qt::Checked == item->checkState(0) ) {
97 /* 若选中的项是树节点,count 会大于 0,否则选中的项是子节点 */
98 if (count > 0) {
99 for (int i = 0; i < count; i++) {
100 /* 子节点全选 */
101 item->child(i)->setCheckState(0, Qt::Checked);
102 }
103 } else {
104 /* 子节点处理 */
105 updateParentItem(item);
106 }
107 /* 若顶层树节点取消选中时 */
108 } else if (Qt::Unchecked == item->checkState(0)) {
109 if (count > 0){
110 /* 若选中的项是树节点,count 会大于 0,否则选中的项是子节点 */
111 for (int i = 0; i < count; i++) {
112 /* 子节点全不选 */
113 item->child(i)->setCheckState(0, Qt::Unchecked);
114 }
115 } else {
116 /* 子节点处理 */
117 updateParentItem(item);
118 }
119 }
120 }
121
122 MainWindow::~MainWindow()
123 {
124 }
在源文件“main.cpp”具体代码由新建项目时生成,无改动。
程序编译运行的结果如下。下图为全选时的状态,好比要群发信息时全选联系人的场景。当选中树节点同事时,子节点(关羽、刘备、张飞)将全选;当树节点同事未选中时,子节点(关羽、刘备、张飞)的状态为未选中;当子节点(关羽、刘备、张飞)选中且不全选时,树节点同事的状态将为半选状态。
QTableWidget 继承 QTableView。QTableWidget 类提供了一个带有默认模型的基于项的表视图。表小部件为应用程序提供标准的表显示工具。QTableWidget 中的项由 QTableWidgetItem 提供。
例 47_qtablewidget,TabelWidget 表格(难度:简单),本例使用一个 TableWidget,绘制一个表格,同时修改项的标题,在表格里可以直接通过双击进行编辑项里的内容,也可以删除项里的内容等。
在新建例程中不要勾选“Generate form”,默认继承 QMainWindow 类即可。项目新建完成,如下图。
在头文件“mainwindow.h”具体代码如下。
1 #ifndef MAINWINDOW_H
2 #define MAINWINDOW_H
3
4 #include <QMainWindow>
5 #include <QTableWidget>
6
7 class MainWindow : public QMainWindow
8 {
9 Q_OBJECT
10
11 public:
12 MainWindow(QWidget *parent = nullptr);
13 ~MainWindow();
14
15 private:
16 /* QTabelWidget 表格 */
17 QTableWidget *tableWidget;
18
19 /* QTabelWidgetItem 表格数据(项) */
20 QTableWidgetItem *tableWidgetItem[4];
21
22 };
23 #endif // MAINWINDOW_H
在源文件“mainwindow.cpp”具体代码如下。
1 #include "mainwindow.h"
2
3 MainWindow::MainWindow(QWidget *parent)
4 : QMainWindow(parent)
5 {
6 /* 设置主窗体的大小与位置 */
7 this->setGeometry(0, 0, 800, 480);
8
9 /* 实例化 */
10 tableWidget = new QTableWidget(this);
11 /* 设置 tableWidget 表居中 */
12 setCentralWidget(tableWidget);
13 /* 设置列数 */
14 tableWidget->setColumnCount(2);
15 /* 设置行数 */
16 tableWidget->setRowCount(2);
17 /* 使用标签设置水平标题标签 */
18 tableWidget->setHorizontalHeaderLabels(
19 QStringList()<<"姓名"<<"性别"
20 );
21
22 /* 字符串类型链表 */
23 QList <QString> strList;
24 strList<<"小明"<<"小红"<<"男"<<"女";
25
26 for (int i = 0; i < 4; i++) {
27 /* 实例化 */
28 tableWidgetItem[i] = new QTableWidgetItem(strList[i]);
29 /* 设置文本居中对齐 */
30 tableWidgetItem[i]->setTextAlignment(Qt::AlignCenter);
31 }
32 /* 插入数据,表的 index 就是一个二维数组数据 */
33 tableWidget->setItem(0, 0, tableWidgetItem[0]);
34 tableWidget->setItem(1, 0, tableWidgetItem[1]);
35 tableWidget->setItem(0, 1, tableWidgetItem[2]);
36 tableWidget->setItem(1, 1, tableWidgetItem[3]);
37
38 }
39
40 MainWindow::~MainWindow()
41 {
42 }
在源文件“main.cpp”具体代码由新建项目时生成,无改动。