目录

一. 输入类控件

1.1 Line Edit

录入个人信息

使用正则表达式验证输入框的数据

切换显示密码

1.2 Text Edit

获取多行输入框的内容

验证输入框的各种信号

1.3 Combo Box

使用下拉框模拟麦当劳点餐

从文件中加载下拉框的选项

1.4 Spin Box

调整麦当劳购物车中的份数

1.5 Date Edit  &  Time Edit

实现日期计算器

1.6 Dial

调整窗口透明度

1.7 Slider

调整窗口大小

通过自定义快捷键调整滑动条位置

二. 多元素控件

2.1 List Widget

使用 List Widget

2.2 Table Widget

使用Table Widget

2.2 Tree Widget

使用Tree Widget

三. 容器类控件

3.1 Group  Box

给麦当劳案例加上分组框

3.2 Tab Widget

使用标签页管理多组控件

四. 布局管理器

4.1 垂直布局

使⽤QVBoxLayout 管理多个控件

创建两个QVBoxLayout

4.2 水平布局

使用QHBoxLayout 管理控件

嵌套的 layout

4.3 网格布局

使用QGridLayout 管理元素

设置QGridLayout 中元素的大小比例

设置垂直方向的拉伸系数

4.4 表单布局

使用QFormLayout 创建表单

4.5 spacer

创建一组左右排列的按钮


一. 输入类控件

1.1 Line Edit

QLineEdit 用来表示单行输入框,可以输入一段文本,但是不能换行。

录入个人信息

inputMask 只能进行简单的输入格式校验。

实际开发中,基于正则表达式的方式是更核心的方法。

使用正则表达式验证输入框的数据

此处要求在输入框中输入一个合法的电话号码 (1 开头,11 位,全都是数字). 如果验证不通过,则确定按钮无法点击.

 关于正则表达式
正则表达式是一种在计算机中常用的,使用特殊字符描述一个字符串的特征的机制。在进行字符串匹配时非常有用.

正则表达式的语法还比较复杂,一般都是随用随查,不需要背下来.

如果输入的电话号是合法的,按钮就解除禁用状态,反之,禁用按钮

・使用 QRegExp 创建一个正则表达式对象. "^1\d {10}$" 表示 "以 1 开头,后面跟上任意的 10 个十进制数字".

・使用 QRegExpValidator 创建一个验证器对象. Qt 中内置了四个主要的验证器对象.

QRegularExpressionValidator 在匹配性能上做出了一定优化。但是从使用角度讲,和 QRegExpValidator 差别不大。我们使用 QRegExpValidator 即可。

第一步:先创建正则表达式regExp,然后再去吧正则表达式注册进去lineEdit

第二步:与按钮的能否使用关联起来,这里选的是lineEdit 的textEdited信号

第三步:解释一下参数

・on_lineEdit_textEdited 的参数是当前输入框的内容。

・通过 lineEdit->validator () 获取到内置的验证器。

・通过 validate 方法验证文本是否符合要求。

◦ 第一个参数填写的是要验证的字符串。由于参数要求是 QString& 而不是 const QString&,需要把这个变量复制一下。

◦ 第二个参数是一个 int&,是输出型参数。当验证的字符串不匹配时,返回这个字符串的长度。(没有啥实质作用)。

◦ 返回值是一个枚举。QValidator::Acceptable 表示验证通过,QValidator::Invalid 表示验证不通过

不是电话的格式就不行:

切换显示密码

加一个CheckBox,给CheckBox的toggled信号添加槽函数:

1.2 Text Edit

QTextEdit 表示多行输入框。也是一个富文本 & markdown 编辑器,并且能在内容超出编辑框范围时自动提供滚动条。

获取多行输入框的内容

验证输入框的各种信号

1.3 Combo Box

使用下拉框模拟麦当劳点餐

从文件中加载下拉框的选项

创建文件并编写选项(每个选项占一行)

・使用 ifstream 打开文件
・使用 getline 读取每一行
・使用 QString::fromStdString 把 std::string 转成 QString

1.4 Spin Box

使用 QSpinBox 或者 QDoubleSpinBox 表示"微调框",它是带有按钮的输入框,可以用来输入整数/浮点数,通过点击按钮来修改数值大小。

由于 SpinBox 和 QDoubleSpinBox 用法基本相同,就只介绍 SpinBox 的使用了。

调整麦当劳购物车中的份数

1.5 Date Edit  &  Time Edit

实现日期计算器

上面的代码的daysTo函数有一些问题,1月1日的17点到1月2日的0点,竟然是一天零七个小时。这里换种写法:

1.6 Dial

调整窗口透明度

1.7 Slider

QDial和QSLider都继承QAbstractSlider,用法基本相同:

调整窗口大小

设置最小,最大,当前窗口大小,一次改变的大小:

设置槽

通过自定义快捷键调整滑动条位置

本身的滑动条就可以使用方向键或者page键。这里就自定义一个:

简述一下:先创建两个快捷键cut和cut1代表“-”和“+”,然后需要设置信号的槽函数进行回调,里面槽函数的功能就是获取当前滑动条的值,判断是否越界,和重新设置滑动条的值。对于滑动条的槽函数的触发条件是滑动条的值改变(valueChanged),里面就是改变标签的内容。

此时就可以使用加减号去调整了。

二. 多元素控件

Qt 中提供的多元素控件有:
・QListWidget
・QListView
・QTableWidget
・QTableView
・QTreeWidget
・QTreeView

以 QTableWidget 和 QTableView 为例:

・QTableView 是基于 MVC 设计的控件。QTableView 自身不持有数据,使用 QTableView 的时候需要用户创建一个 Model 对象(比如 QStandardModel),并且把 Model 和 QTableView 关联起来。后续修改 Model 中的数据就会影响 QTableView 的显示;修改 QTableView 的显示也会影响到 Model 中的数据(双向绑定)。

・QTableWidget 则是 QTableView 的子类,对 Model 进行了封装。不需要用户手动创建 Model 对象,直接就可以往 QTableWidget 中添加数据了。

2.1 List Widget

核心信号

使用 List Widget

还能设计选中的槽函数,利用信号:

2.2 Table Widget

使用Table Widget

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 创建 3 ⾏
    ui->tableWidget->insertRow(0);
    ui->tableWidget->insertRow(1);
    ui->tableWidget->insertRow(2);
    // 创建 3 列
    ui->tableWidget->insertColumn(0);
    ui->tableWidget->insertColumn(1);
    ui->tableWidget->insertColumn(2);
    // 给 3 列设定列名
    ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("学号"));
    ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem("姓名"));
    ui->tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem("年龄"));
    // 设置初始数据
    ui->tableWidget->setItem(0, 0, new QTableWidgetItem("1001"));
    ui->tableWidget->setItem(0, 1, new QTableWidgetItem("张三"));
    ui->tableWidget->setItem(0, 2, new QTableWidgetItem("20"));
    ui->tableWidget->setItem(1, 0, new QTableWidgetItem("1002"));
    ui->tableWidget->setItem(1, 1, new QTableWidgetItem("李四"));
    ui->tableWidget->setItem(1, 2, new QTableWidgetItem("21"));
    ui->tableWidget->setItem(2, 0, new QTableWidgetItem("1003"));
    ui->tableWidget->setItem(2, 1, new QTableWidgetItem("王五"));
    ui->tableWidget->setItem(2, 2, new QTableWidgetItem("19"));
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_insert_row_clicked()
{
    // 在最后一行后新增
    int rowCount = ui->tableWidget->rowCount();
    ui->tableWidget->insertRow(rowCount);
}

void Widget::on_pushButton_3_clicked()
{
    // 获得要删除的行号
    int curRow = ui->tableWidget->currentRow();
    ui->tableWidget->removeRow(curRow);
}


void Widget::on_pushButton_insert_col_clicked()
{
    // 获取列数
    int colCount = ui->tableWidget->columnCount();
    // 新增这一列
    ui->tableWidget->insertColumn(colCount);
    // 获取输入框中的文字
    QString text = ui->lineEdit->text();
    // 设置文字到新增的那一列
    ui->tableWidget->setHorizontalHeaderItem(colCount,new QTableWidgetItem(text));
}


void Widget::on_pushButton_delete_col_clicked()
{
    // 获取列数
    int curCol = ui->tableWidget->currentColumn();
    ui->tableWidget->removeColumn(curCol);
}

2.2 Tree Widget

使用Tree Widget

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //设置根节点的名字
    ui->treeWidget->setHeaderLabel("动物");

    //新增顶层节点
    QTreeWidgetItem* item = new QTreeWidgetItem();
    //每个节点都可以设置多个列
    item->setText(0,"猫");
    //添加到顶层节点中
    ui->treeWidget->addTopLevelItem(item);

    QTreeWidgetItem* item1 = new QTreeWidgetItem();
    item1->setText(0,"狗");
    ui->treeWidget->addTopLevelItem(item1);

    QTreeWidgetItem* item2 = new QTreeWidgetItem();
    item2->setText(0,"中华田园猫");
    item->addChild(item2);

    QTreeWidgetItem* item3 = new QTreeWidgetItem();
    item3->setText(0,"布偶猫");
    item->addChild(item3);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_insert_top_clicked()
{
    // 获取输入框中的内容
    const QString& text = ui->lineEdit->text();
    // 需要构造QTreeWidgetItem对象
    QTreeWidgetItem* item = new QTreeWidgetItem();
    item->setText(0,text);
    ui->treeWidget->addTopLevelItem(item);
}

void Widget::on_pushButton_insert_clicked()
{
    // 获取选中的节点的名称
    QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();
    if(!currentItem) return;
    // 获取输入框中的内容
    const QString& text = ui->lineEdit->text();
    // 需要构造QTreeWidgetItem对象
    QTreeWidgetItem* item = new QTreeWidgetItem();
    item->setText(0,text);
    currentItem->addChild(item);
}

void Widget::on_pushButton_delete_clicked()
{
    QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();
    if(!currentItem) return;
    // 删除选中的元素,需要获取父元素
    QTreeWidgetItem* parent = currentItem->parent();
    if(parent == nullptr)
    {
        //顶层元素
        int index = ui->treeWidget->indexOfTopLevelItem(currentItem);
        ui->treeWidget->takeTopLevelItem(index);
    }
    else
    {
        //普通元素,通过父元素删除
        parent->removeChild(currentItem);
    }
}

三. 容器类控件

3.1 Group  Box

给麦当劳案例加上分组框

3.2 Tab 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* label = new QLabel(ui->tab);//注意不在是Widget了
    label->setText("标签页一");
    label->resize(100,50);

    QLabel* label2 = new QLabel(ui->tab_2);//注意不在是Widget了
    label2->setText("标签页二");
    label2->resize(100,50);
}

Widget::~Widget()
{
    delete ui;
}



void Widget::on_pushButton_clicked()
{
    // 使用addTab
    // 参数一:指定一个QWidget
    // 参数二;指定标签页的标题,标题名字就叫做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::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;
}

简述一下:首先就是需要注意一下关于父类,这里的标签的父类不再是this指针的Widget了。执行按钮添加的操作时,需要我们新建一个QWidget对象,还需要获取标签页的整数,因为是尾插。执行addTab操作时,要注意两个参数,第一个参数是对象,第二个参数是名称。

四. 布局管理器

之前使用 Qt 在界面上创建的控件,都是通过 “绝对定位” 的方式来设定的。

也就是每个控件所在的位置,都需要计算坐标,最终通过 setGeometry 或者 move 方式摆放过去。

这种设定方式其实并不方便,尤其是界面如果内容比较多,不好计算。而且一个窗口大小往往是可以调整的,按照绝对定位的方式,也无法自适应窗口大小。

因此 Qt 引入 “布局管理器”(Layout)机制,来解决上述问题。

4.1 垂直布局

使⽤QVBoxLayout 管理多个控件

即使我们随意的控制窗口的大小,按钮都会自动的改变大小,适配窗口

通过代码,好像只能设置一个布局管理器?

创建两个QVBoxLayout

通过GUI

只不过当前这些按钮的位置不能随着窗口大小自动变化。

通过 Qt Designer 创建的布局管理器,其实是先创建了一个 widget,并且给这个 widget 设置过 geometry 属性,之后再把 layout 设置到这个 widget 中。

实际上,一个 widget 只能包含一个 layout。

如果打开 ui 文件的原始 XML 代码,就能看到其中的具体实现逻辑。

在这种情况下,layout 并非直接作为窗口 widget 的布局管理器,而是属于那个被预先设置了固定 geometry 的子 widget,因此当窗口大小改变时,这个 layout 无法跟随窗口尺寸自动调整 —— 本质是因为它的 “载体 widget”(子 widget)被固定了位置和尺寸,导致 layout 失去了自适应窗口的基础。

4.2 水平布局

使用QHBoxLayout 管理控件

嵌套的 layout

实际上就是谁去使用setLayout 的问题:

4.3 网格布局

使用QGridLayout 管理元素

设置QGridLayout 中元素的大小比例

设置垂直方向的拉伸系数

注意要设置按钮的垂直和水平方向都要舒展开:

#include "widget.h"
#include "ui_widget.h"

#include <QPushButton>
#include <QGridLayout>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 创建 6 个按钮
    QPushButton* btn1 = new QPushButton("按钮1");
    QPushButton* btn2 = new QPushButton("按钮2");
    QPushButton* btn3 = new QPushButton("按钮3");
    QPushButton* btn4 = new QPushButton("按钮4");
    QPushButton* btn5 = new QPushButton("按钮5");
    QPushButton* btn6 = new QPushButton("按钮6");

    QGridLayout* layout = new QGridLayout();
    layout->addWidget(btn1, 0, 0);
    layout->addWidget(btn2, 0, 1);
    layout->addWidget(btn3, 1, 0);
    layout->addWidget(btn4, 1, 1);
    layout->addWidget(btn5, 2, 0);
    layout->addWidget(btn6, 2, 1);


    // 设置按钮的 sizePolicy, 此时按钮的⽔平⽅向和垂直⽅向都会尽量舒展开
    btn1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    btn2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    btn3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    btn4->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    btn5->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    btn6->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    // 设置拉伸⽐例
    //    // 第 0 列拉伸⽐例设为 1;
    //    layout->setColumnStretch(0, 1);
    //    // 第 1 列拉伸⽐例设为 0, 即为固定⼤⼩, 不参与拉伸
    //    layout->setColumnStretch(1, 0);
    //    // 第 2 列拉伸⽐例设为 3, 即为第 2 列的宽度是第 0 列的 3 倍
    //    layout->setColumnStretch(2, 3);
    // 设置拉伸⽐例
    // 第 0 ⾏拉伸⽐例设为 1;
    layout->setRowStretch(0, 1);
    // 第 1 ⾏拉伸⽐例设为 0, 即为固定⼤⼩, 不参与拉伸
    layout->setRowStretch(1, 0);
    // 第 2 ⾏拉伸⽐例设为 3, 即为第 2 ⾏的宽度是第 0 ⾏的 3 倍
    layout->setRowStretch(2, 3);

    // 设置 layout 到窗⼝中.
    this->setLayout(layout);

}

Widget::~Widget()
{
    delete ui;
}

4.4 表单布局

使用QFormLayout 创建表单

• 使用 addRow 方法来添加一行。每行包含两个控件,第一个控件固定是 QLabel / 文本,第二个控件则可以是任意控件。

• 如果把第一个参数填写为 NULL,则该行的左侧不显示任何内容。

4.5 spacer

空白

创建一组左右排列的按钮

指定高度和宽度,还要注意顺序

QT designer也有:

Logo

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

更多推荐