1.多元素控件
Qt 中提供的多元素控件有:
• QListWidget
• Q ListView
• Q TableWidget
• Q TableView
• Q TreeWidget
• Q TreeView
xxView是更底层的实现;XWidget是基于xxView封装而来的。
此处xxView只是负责实现了视图,不负责数据如何存储表示,更不负责数据和视图之间的交互。
因此如果使用xxView就需要程序员自己实现model和controller的部分。操作比较繁琐。xxWidget基于xxView同时把model和controller都帮我们实现好了,拿过来过来就可以使用.xxWidget提供了功能很方便的api,让我们直接就用。
1.1 1 List Widget
使⽤ QListWidget 能够显⽰⼀个纵向的列表.
代码如下:
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 往这里添加一些元素
ui->listWidget->addItem("C++");
ui->listWidget->addItem("Java");
ui->listWidget->addItem("Python");
// 在 QListWidgetItem 中, 可以设置字体属性, 设置图标, 设置文字大小, 设置是否被选中等状态~~
// ui->listWidget->addItem(new QListWidgetItem("C++"));
// ui->listWidget->addItem(new QListWidgetItem("Java"));
// ui->listWidget->addItem(new QListWidgetItem("Python"));
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_insert_clicked()
{
// 1. 先获取到输入框中的内容.
const QString& text = ui->lineEdit->text();
// 2. 添加到 QListWidget 中
ui->listWidget->addItem(text);
}
void Widget::on_pushButton_delete_clicked()
{
// 1. 先获取到被选中的元素是哪个.
int row = ui->listWidget->currentRow();
if (row < 0) {
return;
}
// 2. 按照行号来删除元素
ui->listWidget->takeItem(row);
}
void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
// 通过这个槽函数来感知到变化.
if (current != nullptr) {
qDebug() << "当前选中的元素: " << current->text();
}
if (previous != nullptr) {
qDebug() << "上次选中的元素: " << previous->text();
}
}
执行结果如下:
1.2 Table Widget
使⽤ QTableWidget 表⽰⼀个表格控件.⼀个表格中包含若⼲⾏,每⼀⾏⼜包含若⼲列. 表格中的每个单元格,是⼀个 QTableWidgetItem 对象
1.3 Tree Widget
使⽤ QTreeWidget 表⽰⼀个树形控件.⾥⾯的每个元素,都是⼀个 QTreeWidgetItem ,每个 QTreeWidgetItem 可以包含多个⽂本和图标,每个⽂本/图标为⼀个列.
可以给 QTreeWidget 设置顶层节点(顶层节点可以有多个),然后再给顶层节点添加⼦节点,从⽽构成 树形结构.
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置根节点的名字
ui->treeWidget->setHeaderLabel("动物");
// 新增顶层节点
QTreeWidgetItem* item1 = new QTreeWidgetItem();
// 每个节点都可以设置多个列. 此处为了简单就只设置一列了.
item1->setText(0, "猫");
// 添加到顶层节点中.
ui->treeWidget->addTopLevelItem(item1);
// 新增顶层节点
QTreeWidgetItem* item2 = new QTreeWidgetItem();
// 每个节点都可以设置多个列. 此处为了简单就只设置一列了.
item2->setText(0, "狗");
// 添加到顶层节点中.
ui->treeWidget->addTopLevelItem(item2);
// 新增顶层节点
QTreeWidgetItem* item3 = new QTreeWidgetItem();
// 每个节点都可以设置多个列. 此处为了简单就只设置一列了.
item3->setText(0, "鸟");
// 添加到顶层节点中.
ui->treeWidget->addTopLevelItem(item3);
// 添加一些子节点
QTreeWidgetItem* item4 = new QTreeWidgetItem();
item4->setText(0, "中华田园猫");
item1->addChild(item4);
QTreeWidgetItem* item5 = new QTreeWidgetItem();
item5->setText(0, "布偶猫");
item1->addChild(item5);
QTreeWidgetItem* item6 = new QTreeWidgetItem();
item6->setText(0, "暹罗猫");
item1->addChild(item6);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_insertTopLevelItem_clicked()
{
// 获取到输入框中的内容
const QString& text = ui->lineEdit->text();
// 构造一个 QTreeWidgetItem
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, text);
// 添加到顶层节点中
ui->treeWidget->addTopLevelItem(item);
}
void Widget::on_pushButton_insertItem_clicked()
{
// 获取到当前选中的节点
QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();
if (currentItem == nullptr) {
return;
}
// 获取到输入框的内容
const QString& text = ui->lineEdit->text();
// 构造一个 QTreeWidgetItem
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, text);
// 插入到选中节点的子节点中
currentItem->addChild(item);
}
void Widget::on_pushButton_deleteItem_clicked()
{
// 获取到选中的元素
QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();
if (currentItem == nullptr) {
return;
}
// 删除选中的元素, 需要先获取到父元素, 通过父元素进行删除
QTreeWidgetItem* parent = currentItem->parent();
if (parent == nullptr) {
// 顶层元素
int index = ui->treeWidget->indexOfTopLevelItem(currentItem);
ui->treeWidget->takeTopLevelItem(index);
} else {
// 普通元素
parent->removeChild(currentItem);
}
}
运行结果如下:
上述这几个控件相关的操作,数据都是在内存中保存的.无论在界面上做任何操作,重新运行程序,之前的数据就都没了。
如果要想让数据能够重启也不丢失,就需要编写更多的代码吧内存存储的数据获取到,写入到文件中,并且在下次运行的时候从文件加载数据。
2. 容器类控件
多元素控件,包含的内容,是一个一个的自定义好的“item”对象
容器类控件,包含的内容是前面已经学过的各种控件了.QPushButton,QLineEditQLabel等.QGroupBox分组框,QTableWidget标签页
2.1 GroupBox
当一个界面比较复杂的时候,包含了很多控件的时候。分组框就可以把具有关联关系的控件,组织到一起。就只是为了让界面看起来更好看一点。
使用页面编辑效果如下:
2.2 TabWidget
使⽤ QTabWidget 实现⼀个带有标签⻚的控件,可以往⾥⾯添加⼀些widget.进⼀步的就可以通过标 签⻚来切换.
图形化界面操作初始化如下:
#include "widget.h"
#include "ui_widget.h"
#include <QLabel>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 先在每个标签页中, 添加一个 Label
QLabel* label1 = new QLabel(ui->tab);
label1->setText("标签页1");
label1->resize(100, 50);
QLabel* label2 = new QLabel(ui->tab_2);
label2->setText("标签页2");
label2->resize(100, 50);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
// 使用 addTab 方法来创建新的标签页.
// 参数1 要指定一个 QWidget.
// 参数2 指定这个标签页的 text (标题), 此处标题就叫做 Tab + 数字
int count = ui->tabWidget->count(); // 获取到标签页的数量
QWidget* w = new QWidget();
ui->tabWidget->addTab(w, QString("Tab ") + QString::number(count + 1));
// 添加一个 QLabel 显示内容
QLabel* label = new QLabel(w);
label->setText(QString("标签页 ") + QString::number(count + 1));
label->resize(100, 50);
// 设置新标签页被选中
ui->tabWidget->setCurrentIndex(count);
}
void Widget::on_pushButton_2_clicked()
{
// 获取到当前选中的标签页的下标
int index = ui->tabWidget->currentIndex();
// 删除标签页
ui->tabWidget->removeTab(index);
}
void Widget::on_tabWidget_currentChanged(int index)
{
qDebug() << "当前选中的标签页是: " << index;
}
效果执行:
3. 布局管理器
3.1 垂直布局
使⽤ QVBoxLayout 表⽰垂直的布局管理器.V是vertical 的缩写。
Layout 只是⽤于界⾯布局,并没有提供信号.
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建三个按钮, 使用垂直布局管理器管理起来.
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");
// 创建布局管理器
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
// 把布局管理器添加到窗口中.
this->setLayout(layout);
}
Widget::~Widget()
{
delete ui;
}
执行效果如下:
一般来说,每个widget中只能设置一个布局管理器。
实例:在一个widget中设置多个布局管理器
每个widget中只能设置一个布局管理器
如果在代码中创建layout,其实是只创建了一个layout
如果在QtDesigner中创建的layout,先创建了一个Widget,然后再在这个新的Widget中添加了一个layout.
3.2 ⽔平布局
使⽤ QHBoxLayout 表⽰垂直的布局管理器.H是 horizontal 的缩写 。
布局管理器之间也能进行嵌套。
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建垂直的布局管理器
QVBoxLayout* vlayout = new QVBoxLayout();
this->setLayout(vlayout);
// 添加两个按钮进去
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
vlayout->addWidget(button1);
vlayout->addWidget(button2);
// 创建水平的布局管理器
QHBoxLayout* hlayout = new QHBoxLayout();
// 添加两个按钮进去
QPushButton* button3 = new QPushButton("按钮3");
QPushButton* button4 = new QPushButton("按钮4");
hlayout->addWidget(button3);
hlayout->addWidget(button4);
// 把水平布局管理器添加到垂直布局管理器内部
vlayout->addLayout(hlayout);
}
Widget::~Widget()
{
delete ui;
}
效果如下:
3.3 ⽹格布局
Qt 中还提供了 QGridLayout ⽤来实现⽹格布局的效果.可以达到M*N的这种⽹格的效果
刚创建的布局管理器,这里的控件尺寸都是均等的。当需要创建出尺寸不同的控件的时候,就可以通过拉伸系数来设置,拉伸系数就相当于设置控件之间尺寸的“比例“。
// 设置水平拉伸系数.
layout->setColumnStretch(0, 0);
layout->setColumnStretch(1, 1);
layout->setColumnStretch(2, 2);
由于按钮垂直方向默认没有拉伸开(水平方向默认是拉伸的)因此垂直方向不会受到拉伸系数的影响了,要想让垂直方向的拉伸系数生效,就需要让按钮先能够拉伸展开。
3.4 表单布局
除了上述的布局管理器之外,Qt还提供了QFormLayout,属于是QGridLayout的特殊情况,专门用于实现两列表单的布局。这种表单布局多用于让用户填写信息的场景,左侧列为提示,右侧列为输入框
#include "widget.h"
#include "ui_widget.h"
#include <QFormLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置成 3 行 2 列.
QFormLayout* layout = new QFormLayout();
this->setLayout(layout);
// 创建 3 个 label 作为第一列
QLabel* label1 = new QLabel("姓名");
QLabel* label2 = new QLabel("年龄");
QLabel* label3 = new QLabel("电话");
// 创建 3 个 输入框 作为第二列
QLineEdit* edit1 = new QLineEdit();
QLineEdit* edit2 = new QLineEdit();
QLineEdit* edit3 = new QLineEdit();
// 把上述控件添加到表单布局中
layout->addRow(label1, edit1);
layout->addRow(label2, edit2);
layout->addRow(label3, edit3);
// 创建一个 "提交按钮"
QPushButton* button = new QPushButton("提交");
layout->addRow(nullptr, button);
}
Widget::~Widget()
{
delete ui;
}
3.5 Spacer
使⽤布局管理器的时候,可能需要在控件之间,添加⼀段空⽩.就可以使⽤ QSpacerItem 来表⽰.
QHBoxLayout* layout = new QHBoxLayout();
this->setLayout(layout);
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
// 创建 spacer 使两个按钮之间存在空白.
QSpacerItem* spacer = new QSpacerItem(200, 20);
// 当前是要把空白添加到两个按钮之间. 此处 add 的顺序就是把 addSpacerItem 放到中间了.
layout->addWidget(button1);
layout->addWidget(button2);
layout->addSpacerItem(spacer);
ps:对于qt的部分控件的学习就到这里了,谢谢观看!!!