Qt——常用Widget(控件)

发布于:2025-08-16 ⋅ 阅读:(12) ⋅ 点赞:(0)

常用控件 Widget

需要说明,此处说明的控件都继承于QWiget,因此之前所说的控件属性,和相关API,在这里的控件都适用

按钮类控件

QPushButton

QPushButton继承于QAbstractButtonQAbstractButton是一个抽象类

  • 其派生出类其他按钮,其内部实现了这些按钮包含的公共功能

  • 其中包含了纯虚函数,无法创建出实例对象

在这里插入图片描述

QAbstractButton中,和QPushButton相关的重要属性

属性 说明
text 按钮中的文本
icon 按钮中的图标
iconSize 按钮中图标的尺寸
shortCut 按钮对应的快捷键
autoRepeat 按钮是否会重复触发. 当鼠标左键按住不放时,
如果设为 true, 则会持续产生鼠标点击事件;
如果设为 false, 则必须释放鼠标, 再次按下鼠标时才能产生点击事件.
(相当于游戏手柄上的 “连发” 效果)
autoRepeatDelay 重复触发的延时时间. 按住按钮多久之后, 开始重复触发.
autoRepeatInterval 重复触发的周期.

例如:

设置按钮图标:

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

    QIcon icon(":/avatar");
    ui->pushButton->setIcon(icon);
    ui->pushButton->setIconSize(QSize(50, 50));
}
  • QSize是一个用于描述大小的类,两个参数分别表示宽和高

在这里插入图片描述

设置快捷键:

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

    QIcon iconTarget(":/avatar");
    QIcon iconLeft(":/left");
    QIcon iconRight(":/right");
    QIcon iconUp(":/up");
    QIcon iconDown(":/down");

    ui->pushButtonTarget->setIcon(iconTarget);
    ui->pushButtonTarget->setIconSize(QSize(70, 70));

    ui->pushButtonUp->setIcon(iconUp);
    ui->pushButtonUp->setIconSize(QSize(50, 50));

    ui->pushButtonDown->setIcon(iconDown);
    ui->pushButtonDown->setIconSize(QSize(50, 50));

    ui->pushButtonLeft->setIcon(iconLeft);
    ui->pushButtonLeft->setIconSize(QSize(50, 50));

    ui->pushButtonRight->setIcon(iconRight);
    ui->pushButtonRight->setIconSize(QSize(50, 50));

    // // 可以通过按键名字的方式,直接设置快捷键
    // ui->pushButtonUp->setShortcut(QKeySequence("w"));
    // ui->pushButtonDown->setShortcut(QKeySequence("s"));
    // ui->pushButtonLeft->setShortcut(QKeySequence("a"));
    // ui->pushButtonRight->setShortcut(QKeySequence("d"));

    // 可以通过枚举的方式,设置快捷键
    ui->pushButtonUp->setShortcut(QKeySequence(Qt::Key_W));
    ui->pushButtonDown->setShortcut(QKeySequence(Qt::Key_S));
    ui->pushButtonLeft->setShortcut(QKeySequence(Qt::Key_A));
    ui->pushButtonRight->setShortcut(QKeySequence(Qt::Key_D));

    // // 也可以设置组合键
    // ui->pushButtonUp->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_W));
    // ui->pushButtonDown->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
    // ui->pushButtonLeft->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_A));
    // ui->pushButtonRight->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D));

    // 设置鼠标的自动连发
    ui->pushButtonUp->setAutoRepeat(true);
    ui->pushButtonDown->setAutoRepeat(true);
    ui->pushButtonLeft->setAutoRepeat(true);
    ui->pushButtonRight->setAutoRepeat(true);
}
  • QKeySequence:表示按键序列,说明快捷键可以不是一个按键,也可以是一组按键
  • 键盘快捷键默认是支持连发的,但是鼠标默认不支持;如果要鼠标支持连发,就需要启用autoRepeat属性

效果:

在这里插入图片描述


QRadioButton

单选按钮

radioButton同样继承于QAbstractButton,上面介绍道的属性和方法同样适用

下面为QAbstractButtonradioButton关联较大的属性:

属性 说明
checkable 是否能选中
checked 是否已经被选中. checkable 是 checked 的前提条件.
autoExclusive 是否排他.
选中一个按钮之后是否会取消其他按钮的选中.
对于 QRadioButton 来说默认就是排他的.

例如:

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

    // 设置默认选项
    ui->radioButtonMale->setChecked(true);
    ui->label->setText("性别:男");

    // 禁用 其他 选项
    ui->radioButtonOther->setCheckable(false);
}

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



void Widget::on_radioButtonMale_clicked()
{
    ui->label->setText("性别:男");
}


void Widget::on_radioButtonFemale_clicked()
{
    ui->label->setText("性别:女");
}


void Widget::on_radioButtonOther_clicked()
{
    ui->label->setText("性别:其他");
}

效果

在这里插入图片描述

可以看到,尽管按钮其他被禁用了无法被选中,但是其对应的点击事件却可以触发。

即:**setCheckable(false)**只能让按钮无法被选中,但是仍可以触发对应的点击事件

又例如,我们可以利用QRadioButton来实现一个点餐系统:
在这里插入图片描述

直接运行:

在这里插入图片描述

可以看到,由于QRadioButton具有排他性,这就导致了我们想分别选择主食,荤菜,素材,但是只能在所有的菜品中选择一个。

为了解决这个问题,就需要用到QButtonGroupQButtonGroup可以针对单选按钮进行分组,我们将上面的按钮分成三组,就可以解决问题了

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

    QButtonGroup* buttonGroup1 = new QButtonGroup(this);
    QButtonGroup* buttonGroup2 = new QButtonGroup(this);
    QButtonGroup* buttonGroup3 = new QButtonGroup(this);

    buttonGroup1->addButton(ui->radioButton_1);
    buttonGroup1->addButton(ui->radioButton_2);
    buttonGroup1->addButton(ui->radioButton_3);

    buttonGroup2->addButton(ui->radioButton_4);
    buttonGroup2->addButton(ui->radioButton_5);
    buttonGroup2->addButton(ui->radioButton_6);

    buttonGroup3->addButton(ui->radioButton_7);
    buttonGroup3->addButton(ui->radioButton_8);
    buttonGroup3->addButton(ui->radioButton_9);
}

效果:

在这里插入图片描述


QCheckBox

表示复选按钮,可以选择多个

其关注的属性,同样是:

属性 说明
checkable 是否能选中
checked 是否已经被选中. checkable 是 checked 的前提条件.

例如:

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

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

void Widget::on_pushButton_clicked()
{
    QString str("今日计划: ");
    if (ui->checkBox->isChecked()) {
        str += "写代码 ";
    }
    if (ui->checkBox_2->isChecked()) {
        str += "打游戏 ";
    }
    if (ui->checkBox_3->isChecked()) {
        str += "锻炼 ";
    }

    ui->label->setText(str);
}

效果:

在这里插入图片描述


显示类控件

QLabel

核心的属性:

属性 说明
text QLabel 中的文本
textFormat 文本的格式.
- Qt::PlainText 纯文本
- Qt::RichText 富文本(支持 html 标签)
- Qt::MarkdownText markdown 格式
- Qt::AutoText 根据文本内容自动决定文本格式.
pixmap QLabel 内部包含的图片.
scaledContents 设为 true 表示内容自动拉伸填充 QLabel
设为 false 则不会自动拉伸
alignment 对齐方式.
可以设置水平和垂直方向如何对齐.
wordWrap 设为 true 内部的文本会自动换行.
设为 false 则内部文本不会自动换行.
indent 设置文本缩进. 水平和垂直方向都生效.
margin 内部文本和边框之间的边距.
不同于 indent, 但是是上下左右四个方向都同时有效.
而 indent 最多只是两个方向有效(具体哪两个方向有效取决于 alignment )
openExternalLinks 是否允许打开一个外部的链接.
(当 QLabel 文本内容包含 url 的时候涉及到)
buddy 给 QLabel 关联一个 “伙伴” , 这样点击 QLabel 时就能激活对应的伙伴.
例如伙伴如果是一个 QCheckBox, 那么该 QCheckBox 就会被选中.
  1. 文本格式textFormat

    Widget::Widget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        ui->label->setTextFormat(Qt::PlainText);
        ui->label->setText("这是一段纯文本");
    
        ui->label_2->setTextFormat(Qt::RichText);
        ui->label_2->setText("<b> 这是一段富文本 </b>");
    
        ui->label_3->setTextFormat(Qt::MarkdownText);
        ui->label_3->setText("- 这是一段 markdown 文本");
    }
    

    效果:

    在这里插入图片描述

  2. 填充图片 pixmax

    Widget::Widget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        QLabel* label = new QLabel(this);
        label->setGeometry(0, 0, this->geometry().width(), this->geometry().height());  // 设置Label充满整个窗口
    
        label->setPixmap(QPixmap(":/up"));
        label->setScaledContents(true); // 让图片填充到整个Lable
    }
    

    效果:

    在这里插入图片描述

    • 可以看到,虽然程序运行后图片确实填充到了整个窗口,但是如果我们之后缩放窗口,图片就不能继续填充了
    • 这是因为,图片被放在了Label中,而这又是在构造函数就初始化确定好了
    • 我们之后移动窗口,并不能改变Label的属性,如果我们想要在移动窗口的同时,让图片保持填充,就需要做到Label跟随窗口大小的变化,自行适配

初识事件

为了解决这个问题,就会涉及到”事件“这一概念

Qt中表示用户的操作,有两类概念:信号、事件

当用户拖拽修改窗口大小的时候,就会触发resize事件

  • resize这样的事件,是连续变化
  • 例如,把窗口尺寸从A拖动到B的这个过程中,会触发一系列的resize事件

了解了这些,就可以借助resize事件来完成上述功能

  • 可以让Widget窗口类,重写父类QWidgetresizeEvent虚函数
  • 每次触发resize事件时,就会调用这个虚函数,从而重新指定Label尺寸
// widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QResizeEvent>
#include <QLabel>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void resizeEvent(QResizeEvent* event);

private:
    Ui::Widget *ui;
    QLabel* label = nullptr;
};
#endif // WIDGET_H


// widget.cpp
#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 = new QLabel(this);
    label->setGeometry(0, 0, this->geometry().width(), this->geometry().height());  // 设置Label充满整个窗口

    label->setPixmap(QPixmap(":/up"));
    label->setScaledContents(true); // 让图片填充到整个Lable
}

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

void Widget::resizeEvent(QResizeEvent *event)
{
    // event 包含的 size()方法,得到的就是出发事件这一时刻,窗口的大小
    qDebug() << event->size();
    label->setGeometry(0, 0, event->size().width(), event->size().height());
}

效果:

在这里插入图片描述

  1. 设置对齐方式、自动换行、缩进、边距

    Widget::Widget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        // 设置对齐方式
        ui->label->setAlignment(Qt::AlignRight | Qt::AlignBottom);  // 右下方对齐
        ui->label->setText("aaaaaaaaaaaaa");
    
        // 设置自动换行
        ui->label_2->setAlignment(Qt::AlignLeft | Qt::AlignTop);
        ui->label_2->setWordWrap(true);
        ui->label_2->setText("aaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaa");
    
        // 设置自动缩进
        ui->label_3->setWordWrap(true);
        ui->label_3->setIndent(30);	// 30px
        ui->label_3->setText("aaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaa");
    
        // 设置边距
        ui->label_4->setWordWrap(true);
        ui->label_4->setMargin(50);	// 50px
        ui->label_4->setText("aaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaa");
    }
    
    • 需要注意:WordWrap 通常依赖空格或连字符等字符作为换行点。如果文本是连续的长字符串(如 "aaaaaaaaaa..."),Qt 可能找不到合适的换行位置。

    效果:

    在这里插入图片描述

  2. 设置QLabel伙伴

    • Qt中,QLabel中写的文本,时可以指定快捷键的
    • 可以在文本中使用&后面跟上一个字符来表示
    • 例如&A,就表示Alt + A
    • 绑定了伙伴关系之后,通过快捷键就可以选中对应的单选按钮/复选按钮

    例如:

    在这里插入图片描述

    Widget::Widget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        ui->labelA->setBuddy(ui->radioButton);
        ui->labelB->setBuddy(ui->checkBox);
    }
    

    效果:

    在这里插入图片描述


LCD Number

QLCDNumber是一个专门用来显示数字的控件。类似于”老式计算机“

在这里插入图片描述

相关属性:

属性 说明
intValue QLCDNumber 显示的数字值(int)。
value QLCDNumber 显示的数字值(double)。
和 intValue 是联动的。
例如给 value 设为 1.5, intValue 的值就是 2。
另外, 设置 value 和 intValue 的方法名字为 display , 而不是 setValue 或者 setIntValue
digitCount 显示几位数字。
mode 数字显示形式。
1. QLCDNumber::Dec:十进制模式,显示常规的十进制数字。
2. QLCDNumber::Hex:十六进制模式,以十六进制格式显示数字。
3. QLCDNumber::Bin:二进制模式,以二进制格式显示数字。
4. QLCDNumber::Oct:八进制模式,以八进制格式显示数字。
只有十进制的时候才能显示小数点后的内容。
segmentStyle 设置显示风格。
1. QLCDNumber::Flat:平面的显示风格,数字呈现在一个平坦的表面上。
2. QLCDNumber::Outline:轮廓显示风格,数字具有清晰的轮廓和阴影效果。
3. QLCDNumber::Filled:填充显示风格,数字被填充颜色并与背景区分开。
smallDecimalPoint 设置比较小的小数点。

制作一个简单的倒计时:

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

#include <QTimer>
#include <QDebug>

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

    ui->lcdNumber->display(6);

    QTimer* timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, [this](){
        int number = ui->lcdNumber->intValue();
        if (number <= 0){
            return;
        }

        ui->lcdNumber->display(number - 1);
    });

    timer->start(1000);	// 1s后触发
}

Widget::~Widget()
{
    delete ui;
}
  • QTimer时Qt的一个定时器类,通过方法start()设置其触发事件
  • QTimer触发时,就会发出一个timeout信号。此时就可以用一个槽函数来关联这个信号,从而更新倒计时

效果:

在这里插入图片描述

可能有同学会疑惑:可不可以直接通过休眠和循环来实现这个计数器呢?我们可以试一下:

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

    ui->lcdNumber->display(6);

    std::thread thread([this](){
        int number = this->ui->lcdNumber->intValue();
        while (true) {
            if (number <= 0) {
                return;
            }

            this->ui->lcdNumber->display(number);
            --number;

            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    });
    // thread.detach();
}
  • 注意,这里之所以要使用线程,原因为:
  • 如果不使用线程,而是直接在原有的线程里直接使用循环,那么就会阻塞Widget构造函数的进行。Widget控件窗口都没有构造好,循环对LCDNumber的修改肯定也是没用的

此时,运行程序会抛出异常:

terminate called without an active exception

这是因为:

为了保证线程安全,Qt要求所有 GUI 操作必须在主线程(GUI 线程)中进行

尽管上述代码在加上thread.detach();后可以正常运行,但仍然建议使用信号槽机制,来对GUI界面进行操作:

在这里插入图片描述


ProgressBar

进度条

在这里插入图片描述

相关属性:

以下是合并后的 Markdown 表格,整合了进度条相关属性及说明:

属性 说明
minimum 进度条最小值
maximum 进度条最大值
value 进度条当前值
alignment 文本在进度条中的对齐方式,可选值:
- Qt::AlignLeft:左对齐
- Qt::AlignRight:右对齐
- Qt::AlignCenter:居中对齐
- Qt::AlignJustify:两端对齐
textVisible 进度条的数字是否可见
orientation 进度条的方向是水平还是垂直
invertAppearance 是否是朝反方向增长进度
textDirection 文本的朝向
format 展示的数字格式,可选值:
- %p:表示进度的百分比(0-100)
- %v:表示进度的数值(0-100)
- %m:表示剩余时间(以毫秒为单位)
- %t:表示总时间(以毫秒为单位)

例如:

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

    QTimer* timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, [this](){
        int val = this->ui->progressBar->value();
        if (val >= 100) {
            return;
        }

        this->ui->progressBar->setValue(val + 5);
    });

    timer->start(100);
}

效果:

在这里插入图片描述


CalendarWidget

日历

核心属性:

属性 说明
selectDate 当前选中的日期
minimumDate 最小日期
maximumDate 最大日期
firstDayOfWeek 每周的第一天(也就是日历的第一列)是周几。
gridVisible 是否显示表格的边框
selectionMode 是否允许选择日期
navigationBarVisible 日历上方标题是否显示
horizontalHeaderFormat 日历上方标题显示的日期格式
verticalHeaderFormat 日历第一列显示的内容格式
dateEditEnabled 是否允许日期被编辑

重要信号

信号 说明
selectionChanged(const QDate&) 当选中的日期发生改变时发出
activated(const QDate&) 当双击一个有效的日期或者按下回车键时发出,形参是一个 QDate 类型,保存了选中的日期
currentPageChanged(int, int) 当年份月份改变时发出,形参表示改变后的新年份和月份

例如:

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

    connect(ui->calendarWidget, &QCalendarWidget::clicked, this, [this](){
        this->ui->label->setText(this->ui->calendarWidget->selectedDate().toString());
    });
}

效果:

在这里插入图片描述


输入类控件

LineEdit

单行输入框,可以输入一段文字,但是不能换行

核心属性:

属性 说明
text 输入框中的文本
inputMask 输入内容格式约束(对输入内容进行简单校验)
maxLength 最大长度
frame 是否添加边框
echoMode 显示方式。
- QLineEdit::Normal:默认值,文本框显示输入文本
- QLineEdit::Password:输入字符隐藏,常用*或=代替
- QLineEdit::NoEcho:不显示任何输入字符
cursorPosition 光标所在位置
alignment 文字对齐方式,设置水平和垂直方向的对齐
dragEnabled 是否允许拖拽
readOnly 是否是只读的(不允许修改)
placeHolderText 输入框内容为空时,显示的提示信息
clearButtonEnabled 是否自动显示“清除按钮”
- 如果输入框没有内容,没有变化
- 如果输入框有内容,那么就会在输入框右侧出现一个按钮,如果点击,就会清空输入框所有内容

信号:

属性(信号) 说明
void cursorPositionChanged(int old, int new) 鼠标移动时发出信号,old 是先前位置,new 是新位置
void editingFinished() 按返回 / 回车键、行编辑失去焦点时发出信号
void returnPressed() 返回 / 回车键按下时发信号;若有验证器,需验证通过才触发
void selectionChanged() 选中文本改变时发出信号
void textChanged(const QString &text) 文本改变(包括代码修改)时发信号,text 为新文本
void textEdited(const QString &text) 文本改变(仅用户编辑,代码修改不触发 )时发信号,text 为新文本

例如:

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

#include <QDebug>
#include <QLineEdit>
#include <QRegularExpressionValidator>


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

    ui->pushButton->setEnabled(false);  // 手机号码正确之前,按钮不允许被按下

    ui->lineEditName->setPlaceholderText("请输入姓名");
    ui->lineEditName->setClearButtonEnabled(true);

    ui->lineEditPassword->setPlaceholderText("请输入密码");
    ui->lineEditPassword->setClearButtonEnabled(true);
    ui->lineEditPassword->setEchoMode(QLineEdit::Password);

    ui->lineEditRePassword->setPlaceholderText("请确认密码");
    ui->lineEditRePassword->setClearButtonEnabled(true);
    ui->lineEditRePassword->setEchoMode(QLineEdit::Password);

    ui->lineEditPhone->setPlaceholderText("请输入手机号");
    ui->lineEditPhone->setClearButtonEnabled(true);
    QRegularExpression regExp("^1[3-9]\\d{9}$");
    ui->lineEditPhone->setValidator(new QRegularExpressionValidator(regExp, this));
	
	//使用ToolButton作为是否显示密码的开关
    ui->toolButton->setIcon(QIcon(":/closeEyes"));
    ui->toolButton_2->setIcon(QIcon(":/closeEyes"));
    ui->toolButton->setCheckable(true);
    ui->toolButton_2->setCheckable(true);
    ui->toolButton->setChecked(false);
    ui->toolButton_2->setChecked(false);
}

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


void Widget::on_pushButton_clicked()
{
    QString sex = ui->radioButton->isChecked()? "男" : "女";

    qDebug() << "姓名:" << ui->lineEditName->text() <<
        "性别:" << sex <<
        "密码:" << ui->lineEditPassword->text() <<
        "手机号:" << ui->lineEditPhone->text();
}


void Widget::on_lineEditPhone_textEdited(const QString &arg1)
{
    QString str = arg1;
    int pos;
    QValidator::State state = ui->lineEditPhone->validator()->validate(str, pos);
    if (state == QValidator::State::Acceptable) {
        ui->pushButton->setEnabled(true);
    } else {
        ui->pushButton->setEnabled(false);
    }
}


void Widget::on_lineEditPassword_textEdited(const QString &arg1)
{
    compare();
}


void Widget::on_lineEditRePassword_textEdited(const QString &arg1)
{
    compare();
}

void Widget::compare()
{
    QString str1 = ui->lineEditPassword->text();
    QString str2 = ui->lineEditRePassword->text();
    if (str1 == str2) {
        ui->labelCheck->setText("密码一致");
    } else {
        ui->labelCheck->setText("密码不一致,重新输入");
    }
}

void Widget::on_toolButton_toggled(bool checked)
{
    if (checked) {
        ui->lineEditPassword->setEchoMode(QLineEdit::Normal);
        ui->toolButton->setIcon(QIcon(":/openEyes"));
    } else {
        ui->lineEditPassword->setEchoMode(QLineEdit::Password);
        ui->toolButton->setIcon(QIcon(":/closeEyes"));
    }
}

void Widget::on_toolButton_2_toggled(bool checked)
{
    if (checked) {
        ui->lineEditRePassword->setEchoMode(QLineEdit::Normal);
        ui->toolButton_2->setIcon(QIcon(":/openEyes"));
    } else {
        ui->lineEditRePassword->setEchoMode(QLineEdit::Password);
        ui->toolButton_2->setIcon(QIcon(":/closeEyes"));
    }
}

注意:

  • 这里的手机号部分,用到了正则表达式:^1[3-9]\\d{9}$

  • 正则表达式,本质上就是一个带有特殊字符的字符串,特殊字符用来表示另一个字符串的特征

  • 例如上面的正则表达式意味:

    • ^1:以1开头
    • [3-9]:第二个数字为 3~9之间的一个数字
    • \\d\d表示任意数字,并用\进行转义
    • {9}:表示前面的元素重复9次
  • 在Qt中,可以使用QRegularExpressionValidator正则表达式验证器进行正则表达式验证

    • 其构造函数需要传入一个QRegularExpression,即一个正则表达式字符串

    • 之后可以调用它的方法,来获取传入的数据是否匹配:

      [override virtual] QValidator::State QRegularExpressionValidator::validate(QString &input, int &pos) const
      
      • input:即为要被校验的字符串
      • pos:输出型参数,如果校验不通过,则会将pos设置为第一次校验失败的位置
      • QValidator::State:枚举类型。Acceptable- 校验通过,Intermediate - 部分匹配(例如对于上面的手机号,用户输入13,后面还没输入,就属于部分匹配,因为用户之后输入的内容可能完全匹配),Invalid - 无效(例如,用户输入010,输入的内容已经完全不匹配规则,故为无效)

效果:

在这里插入图片描述


TextEdit

多行输入框,也是一个 富文本/markdown 编辑器

除了TextEidt外,还有一个多行输入框PlainTextEdit,但是PlainTextEdit只支持纯文本编辑

属性:

属性 说明
markdown 输入框内持有的内容,支持 markdown 格式,能够自动的对 markdown 文本进行渲染成 html
html 输入框内持有的内容,可以支持大部分 html 标签,包括 img 和 table 等
placeHolderText 输入框为空时提示的内容
readOnly 是否是只读的
undoRedoEnable 是否开启 undo/redo 功能

按下 ctrl + z 触发 undo

按下 ctrl + y 触发 redo
autoFormatting 开启自动格式化
tabstopWidth 按下缩进占多少空间
overwriteMode 是否开启覆盖写模式
acceptRichText 是否接收富文本内容
verticalScrollBarPolicy 垂直方向滚动条的出现策略

- Qt::ScrollBarAsNeeded:根据内容自动决定是否需要滚动条,这是默认值

- Qt::ScrollBarAlwaysOff:总是关闭滚动条

- Qt::ScrollBarAlwaysOn:总是显示滚动条
horizontalScrollBarPolicy 水平方向滚动条的出现策略

- Qt::ScrollBarAsNeeded:根据内容自动决定是否需要滚动条,这是默认值

- Qt::ScrollBarAlwaysOff:总是关闭滚动条

- Qt::ScrollBarAlwaysOn:总是显示滚动条

信号:

信号 说明
textChanged() 文本内容改变时触发
selectionChanged() 选中范围改变时触发
cursorPositionChanged() 光标移动时触发
undoAvailable(bool) 可以进行 undo 操作时触发
redoAvailable(bool) 可以进行 redo 操作时触发
copyAvailable(bool) 文本被选中 / 取消选中时触发

例如:

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

#include <QDebug>
#include <QTextCursor>

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

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

void Widget::on_textEdit_textChanged()
{
    qDebug() << "textChanged: " << ui->textEdit->toPlainText();
}

void Widget::on_textEdit_selectionChanged()
{
    QTextCursor cursor = ui->textEdit->textCursor();
    qDebug() << "selectionChanged: " << cursor.selectedText();
}

void Widget::on_textEdit_cursorPositionChanged()
{
    QTextCursor cursor = ui->textEdit->textCursor();
    qDebug() << "cursorPositionChanged: " << cursor.position();
}

void Widget::on_textEdit_copyAvailable(bool b)
{
    qDebug() << "copyAvailable: " << b;
}

void Widget::on_textEdit_redoAvailable(bool b)
{
    qDebug() << "redoAvailable: " << b;
}

void Widget::on_textEdit_undoAvailable(bool b)
{
    qDebug() << "undoAvailable: " << b;
}

效果:

在这里插入图片描述


ComboBox

下拉框

属性:

属性 说明
currentText 当前选中的文本
currentIndex 当前选中的条目下标,从 0 开始计算,无选中条目时值为 -1
editable 是否允许修改;设为 true 时,QComboBox 行为接近 QLineEdit,可设置 validator
iconSize 下拉框图标(小三角)的大小
maxCount 最多允许有的条目数量

方法:

方法 说明
addItem(const QString&) 添加一个条目
currentIndex() 获取当前条目的下标
从 0 开始计算。如果当前没有条目被选中,值为 -1
currentText() 获取当前条目的文本内容

信号:

信号 说明
activated(int) 当用户选择了一个选项时发出
activated(const QString & text) 用户点开下拉框且鼠标划过某选项(未确认选择时触发 )
currentIndexChanged(int) 当前选项改变时发出
currentIndexChanged(const QString & text) 用户明确选择选项(用户或程序操作均触发 )
editTextChanged(const QString & text) 编辑框文本改变时发出(editabletrue 时有效 )

例如:

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

#include <QDebug>
#include <fstream>


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

    std::ifstream file("G:/QtProject/study/edit/source/food.txt");
    std::string str;
    while (std::getline(file, str)) {
        ui->comboBox->addItem(QString::fromStdString(str));
    }
}

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

void Widget::on_pushButton_clicked()
{
    qDebug() << ui->comboBox->currentText();
}

效果:

在这里插入图片描述


SpinBox & DoubleSpinBox

微调框

在这里插入图片描述

属性:

属性 说明
value 存储的数值.
singleStep 每次调整的 “步长”. 按下一次按钮数据变化多少.
displayInteger 数字的进制。例如 displayInteger 设为 10, 则是按照 10 进制表示。设为 2 则为 2 进制表示.
minimum 最小值
maximum 最大值
suffix 后缀
prefix 前缀
wrapping 是否允许换行
frame 是否带边框
alignment 文字对齐方式.
readOnly 是否允许修改
buttonSymbol 按钮上的图标.
- UpDownArrows:上下箭头形式
- PlusMinus:加减号形式
- NoButtons:没有按钮
accelerated 按下按钮时是否为快速调整模式
correctionMode 输入有误时如何修正.
- QAbstractSpinBox::CorrectToPreviousValue:如果用户输入了一个无效的值(例如,在只能显示正整数的 SpinBox 中输入了负数),那么 SpinBox 会恢复为上一个有效值。例如,如果 SpinBox 的初始值是 1,用户输入了 -1(无效),然后 SpinBox 会恢复为 1。
- QAbstractSpinBox::CorrectToNearestValue:如果用户输入了一个无效的值,SpinBox 会恢复为最接近的有效值。例如,如果 SpinBox 的初始值是 1,用户输入了 -1(无效),那么 SpinBox 会恢复为 0。
keyboardTrack 是否开启键盘跟踪.
- 设为 true, 每次在输入框输入一个数字,都会触发一次 valueChanged()textChanged() 信号.
- 设为 false, 只有在最终按下 enter 或者输入框失去焦点,才会触发 valueChanged()textChanged() 信号.

信号:

信号 说明
textChanged(QString) 微调框文本改变时触发,参数 QString 为新的text,含前缀、后缀
valueChanged(int) 微调框数值改变时触发,参数 int 是新的数值

例如:

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

    std::ifstream file("G:/QtProject/study/edit/source/food.txt");
    std::string str;
    while (std::getline(file, str)) {
        ui->comboBox->addItem(QString::fromStdString(str));
    }

    ui->spinBox->setValue(1);
}

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

void Widget::on_pushButton_clicked()
{
    ui->label->setText(ui->comboBox->currentText() + ": " +
                       QString::number(ui->spinBox->value()));
}

效果:

在这里插入图片描述


Dial

旋钮

属性:

属性 说明
value 持有的数值.
minimum 最小值
maximum 最大值
singleStep 按下方向键的时候改变的步长.
pageStep 按下 pageUp / pageDown 的时候改变的步长.
sliderPosition 界面上旋钮显示的初始位置
tracking 外观是否会跟踪数值变化.
默认值为 true. 一般不需要修改.
wrapping 是否允许循环调整.
即数值如果超过最大值, 是否允许回到最小值.(调整过程能否 “套圈”)
notchesVisible 是否显示刻度线
notchTarget 刻度线之间的相对位置.
数字越大, 刻度线越稀疏.

例如,实现一个旋钮,用来调节窗口透明度:

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

    ui->dial->setWrapping(true);
    ui->dial->setMinimum(10);
    ui->dial->setMaximum(1000);
    ui->dial->setNotchesVisible(true);
}

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


void Widget::on_dial_valueChanged(int value)
{
    this->setWindowOpacity((double)value / 1000);
}

效果:

在这里插入图片描述


Slider

滑动条

QSliderQDial都继承于QAbstractSlider,因此用法基本相同

属性 说明
value 持有的数值.
minimum 最小值
maximum 最大值
singleStep 按下方向键的时候改变的步长.
pageStep 按下 pageUp /pageDown 的时候改变的步长.
sliderPosition 滑动条显示的初始位置
tracking 外观是否会跟踪数值变化.
默认值为 true. 一般不需要修改.
orientation 滑动条的方向是水平还是垂直
invertedAppearance 是否要翻转滑动条的方向
tickPosition 刻度的位置.
tickInterval 刻度的密集程度.

例如:实现两个滑动条,调节窗口宽度和高度

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

#include <QDebug>
#include <QDateTime>


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

    ui->horizontalSlider->setMinimum(100);
    ui->horizontalSlider->setMaximum(2000);
    ui->horizontalSlider->setValue(200);
    ui->horizontalSlider->setSingleStep(50);

    ui->verticalSlider->setMinimum(100);
    ui->verticalSlider->setMaximum(2000);
    ui->verticalSlider->setValue(200);
    ui->verticalSlider->setSingleStep(50);
}

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


void Widget::on_verticalSlider_valueChanged(int value)
{
    QRect rect = this->geometry();
    this->setGeometry(rect.x(), rect.y(), rect.width(), value);
}


void Widget::on_horizontalSlider_valueChanged(int value)
{
    QRect rect = this->geometry();
    this->setGeometry(rect.x(), rect.y(), value, rect.height());
}

效果:

在这里插入图片描述
同时学习一下,Qt快捷键的使用:

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

#include <QDebug>
#include <QDateTime>
#include <QShortcut>


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

    ui->horizontalSlider->setMinimum(100);
    ui->horizontalSlider->setMaximum(2000);
    ui->horizontalSlider->setValue(200);
    ui->label->setText("当前值为:"+ QString::number(ui->horizontalSlider->value()));

    QShortcut* shortcut_add = new QShortcut(this);
    shortcut_add->setKey(QKeySequence("="));
    QShortcut* shortcut_sub = new QShortcut(this);
    shortcut_sub->setKey(QKeySequence("-"));

    connect(shortcut_add, &QShortcut::activated, this, [this](){
        int val = this->ui->horizontalSlider->value() + 50;
        if (val < this->ui->horizontalSlider->maximum()) {
            this->ui->horizontalSlider->setValue(val);
        } else {
            this->ui->horizontalSlider->setValue(this->ui->horizontalSlider->maximum());
        }

    });
    connect(shortcut_sub, &QShortcut::activated, this, [this](){
        int val = this->ui->horizontalSlider->value() - 50;
        if (val > this->ui->horizontalSlider->minimum()) {
            this->ui->horizontalSlider->setValue(val);
        } else {
            this->ui->horizontalSlider->setValue(this->ui->horizontalSlider->minimum());
        }
    });
}

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

void Widget::on_horizontalSlider_valueChanged(int value)
{
    ui->label->setText("当前值为:"+ QString::number(ui->horizontalSlider->value()));
}
  • QShortCut:快捷键类,可以为其设置QKeySequence,即快捷键字符串
  • QShortcut::activated:当快捷键被按下时触发该信号

多元素控件

ListWidget

能够显示一个纵向显示的列表

属性:

属性 说明
currentRow 当前被选中的是第几行
count 一共有多少行
sortingEnabled 是否允许排序
isWrapping 是否允许换行
itemAlignment 元素的对齐方式
selectRectVisible 被选中的元素矩形是否可见
spacing 元素之间的间隔

方法:

方法 说明
addItem(const QString& label)
addItem(QListWidgetItem *item)
向列表添加元素(支持字符串标签或 QListWidgetItem 对象)
currentItem() 返回当前选中元素的 QListWidgetItem*
currentRow() 返回当前选中元素的 行号
setCurrentItem(QListWidgetItem* item) 设置选中指定 QListWidgetItem 元素
setCurrentRow(int row) 设置选中指定行的元素
insertItem(const QString& label, int row)
insertItem(QListWidgetItem *item, int row)
在指定行插入元素(支持字符串标签或 QListWidgetItem 对象)
item(int row) 返回第 row 行元素的 QListWidgetItem*
takeItem(int row) 删除指定行元素,返回被删除的 QListWidgetItem*

信号:

方法(信号) 说明
currentItemChanged(QListWidgetItem* current, QListWidgetItem* old) 选中元素变化时触发,参数为当前选中、之前选中的 QListWidgetItem
currentRowChanged(int) 选中元素变化时触发,参数为当前选中元素的行号
itemClicked(QListWidgetItem* item) 点击列表项(元素)时触发,参数是被点击的 QListWidgetItem
itemDoubleClicked(QListWidgetItem* item) 双击列表项时触发,参数是被双击的 QListWidgetItem
itemEntered(QListWidgetItem* item) 鼠标进入列表项区域时触发,参数是对应的 QListWidgetItem

例如:

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

#include <QDebug>
#include <QDateTime>
#include <QShortcut>


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

    ui->listWidget->addItem("C++");
    ui->listWidget->addItem(new QListWidgetItem("Linux"));
    ui->listWidget->addItem(new QListWidgetItem("Qt"));
}

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

void Widget::on_pushButtonAdd_clicked()
{
    QString text = ui->lineEdit->text();
    if (!text.isEmpty()) {
        ui->listWidget->addItem(text);
    }
}

void Widget::on_pushButtonRemove_clicked()
{
    int row = ui->listWidget->currentRow();
    if (row >= 0) {
        ui->listWidget->takeItem(row);
    }
}

void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
	// 一定要检查指针有效性
    if  (current) {
        qDebug() << "现在的元素为" << current->text();
    }
    if (previous) {
        qDebug() << "之前的元素为:" << previous->text();
    }
}

效果:

在这里插入图片描述


TableWidget

表格

方法:

方法 说明
item(int row, int column) 根据行数列数获取指定的 QTableWidgetItem*
setItem(int row, int column, QTableWidgetItem* item) 根据行数列数设置表格中的元素
currentItem() 返回被选中的元素 QTableWidgetItem*
currentRow() 返回被选中元素是第几行
currentColumn() 返回被选中元素是第几列
row(QTableWidgetItem* item) 获取指定 item 是第几行
column(QTableWidgetItem* item) 获取指定 item 是第几列
rowCount() 获取行数
columnCount() 获取列数
insertRow(int row) 在第 row 行处插入新行
insertColumn(int column) 在第 column 列插入新列
removeRow(int row) 删除第 row
removeColumn(int column) 删除第 column
setHorizontalHeaderItem(int column, QTableWidgetItem* item) 设置指定列的表头
setVerticalHeaderItem(int row, QTableWidgetItem* item) 设置指定行的表头

信号:

信号签名 说明
cellClicked(int row, int column) 点击表格单元格时触发,参数为单元格的行、列索引
cellDoubleClicked(int row, int column) 双击表格单元格时触发,参数为单元格的行、列索引
cellEntered(int row, int column) 鼠标进入表格单元格区域时触发,参数为单元格的行、列索引
currentCellChanged(int row, int column, int previousRow, int previousColumn) 选中单元格变化时触发,参数为当前选中单元格行、列,及之前选中的行、列索引

QTableWidgetItem的方法:

方法签名 说明
row() 获取当前项的行索引
column() 获取当前项的列索引
setText(const QString&) 设置单元格文本内容
setTextAlignment(int) 设置文本对齐方式
setIcon(const QIcon&) 设置单元格图标
setSelected(bool) 设置单元格是否选中
setSizeHint(const QSize&) 设置单元格尺寸提示
setFont(const QFont&) 设置单元格文本字体

例如:

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

#include <QDebug>

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

    ui->tableWidget->insertRow(0);
    ui->tableWidget->insertRow(1);
    ui->tableWidget->insertRow(2);
    ui->tableWidget->insertColumn(0);
    ui->tableWidget->insertColumn(1);

    ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("姓名"));
    ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem("性别"));

    ui->lineEdit->setPlaceholderText("请输入列名");
    ui->pushButtonPushLeft->setEnabled(false);
    ui->pushButtonPushRight->setEnabled(false);
}

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

void Widget::on_pushButtonPushUp_clicked()
{
    int row = std::max(ui->tableWidget->currentRow(), 0);

    ui->tableWidget->insertRow(row);

}

void Widget::on_pushButtonPushDown_clicked()
{
    int row = ui->tableWidget->currentRow();

    ui->tableWidget->insertRow(row + 1);
}

void Widget::on_pushButtonPushLeft_clicked()
{
    QString text = ui->lineEdit->text();
    int col = std::max(ui->tableWidget->currentColumn(), 0);

    ui->tableWidget->insertColumn(col);
    ui->tableWidget->setHorizontalHeaderItem(col, new QTableWidgetItem(text));
    ui->lineEdit->clear();

}

void Widget::on_pushButtonPushRight_clicked()
{
    QString text = ui->lineEdit->text();
    int col = ui->tableWidget->currentColumn();

    ui->tableWidget->insertColumn(col + 1);
    ui->tableWidget->setHorizontalHeaderItem(col + 1, new QTableWidgetItem(text));
    ui->lineEdit->clear();
}

void Widget::on_pushButtonPopCol_clicked()
{
    int col = ui->tableWidget->currentColumn();

    if (col >= 0) {
        ui->tableWidget->removeColumn(col);
    }
}

void Widget::on_pushButtonPopRow_clicked()
{
    int row = ui->tableWidget->currentRow();

    if (row >= 0) {
        ui->tableWidget->removeRow(row);
    }
}

void Widget::on_lineEdit_textChanged(const QString &arg1)
{
    if (arg1.isEmpty()){
        ui->pushButtonPushLeft->setEnabled(false);
        ui->pushButtonPushRight->setEnabled(false);
    } else {
        ui->pushButtonPushLeft->setEnabled(true);
        ui->pushButtonPushRight->setEnabled(true);
    }
}

效果:

在这里插入图片描述


TreeWidget

树形控件

这里的树,不考虑顶层的根节点,而是从根节点的下一层开始计算的

在这里插入图片描述

TreeWidget方法:

方法 说明
clear 清空所有子节点
addTopLevelItem(QTreeWidgetItem* item) 新增顶层节点
topLevelItem(int index) 获取指定下标的顶层节点.
topLevelItemCount() 获取顶层节点个数
indexOfTopLevelItem(QTreeWidgetItem* item) 查询指定节点是顶层节点中的下标
takeTopLevelItem(int index) 删除指定的顶层节点.返回 QTreeWidgetItem* 表示被删除的元素
currentItem() 获取到当前选中的节点,返回 QTreeWidgetItem*
setCurrentItem(QTreeWidgetItem* item) 选中指定节点
setExpanded(bool) 展开/关闭节点
setHeaderLabel(const QString& text) 设置 TreeWidget 的 header 名称.
setHeaderHidden(bool) 设置header是否隐藏
setColumnCount 设置列数

TreeWidgetItem属性:

属性 说明
text 持有的文本
textAlignment 文本对齐方式
icon 持有的图表
font 文本字体
hidden 是否隐藏
disabled 是否禁用
expand 是否展开
sizeHint 尺寸大小
selected 是否选中

TreeWidgetItem方法:

方法 说明
addChild(QTreeWidgetItem* child) 新增子节点
childCount() 子节点的个数
child(int index) 获取指定下标的子节点,返回 QTreeWidgetItem*
takeChild(int index) 删除对应下标的子节点
removeChild(QTreeWidgetItem* child) 删除对应的子节点
parent() 获取该元素的父节点

例如:

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

#include <QTreeWidgetItem>
#include <QDebug>

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

    ui->lineEdit->setPlaceholderText("请输入节点名称");
    ui->pushButtonAddNext->setEnabled(false);
    ui->pushButtonAddRoot->setEnabled(false);

    // 设置标题栏名称
    // ui->treeWidget->setHeaderHidden("true");
	
	// 添加两列
    ui->treeWidget->setColumnCount(2);
    ui->treeWidget->setHeaderLabels({"动物", "数量"});

    // 添加顶层节点
    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, "暹罗猫");
    item2->addChild(item5);
}

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

void Widget::on_pushButtonAddRoot_clicked()
{
    QString text = ui->lineEdit->text();
    ui->lineEdit->clear();
    QTreeWidgetItem* item = new QTreeWidgetItem();
    item->setText(0, text);
    ui->treeWidget->addTopLevelItem(item);
}


void Widget::on_pushButtonAddNext_clicked()
{
    // 获取当前选中的节点
    QTreeWidgetItem* root = ui->treeWidget->currentItem();
    if (root) {
        QString text = ui->lineEdit->text();
        ui->lineEdit->clear();
        QTreeWidgetItem* item = new QTreeWidgetItem();
        item->setText(0, text);
        root->addChild(item);
    }
}


void Widget::on_pushButtonRemove_clicked()
{
    QTreeWidgetItem* root = ui->treeWidget->currentItem();
    if (root) {
        QTreeWidgetItem* parent = root->parent();
        if (parent == nullptr) {
            int index = ui->treeWidget->indexOfTopLevelItem(root);
            ui->treeWidget->takeTopLevelItem(index);
        } else {
            parent->removeChild(root);
        }
    }
}


void Widget::on_lineEdit_textChanged(const QString &arg1)
{
    if (arg1.isEmpty()) {
        ui->pushButtonAddNext->setEnabled(false);
        ui->pushButtonAddRoot->setEnabled(false);
    } else {
        ui->pushButtonAddNext->setEnabled(true);
        ui->pushButtonAddRoot->setEnabled(true);
    }
}

效果:

在这里插入图片描述


容器类控件

多元素空间,包含的内容是,一个个的自定义好的Item对象

容器类控件, 包含的内容是,前面所讲的各种控件,如PushButton,LineEdit

GroupBox

在这里插入图片描述

属性:

属性 说明
title 分组框的标题
alignment 分组框内部内容的对齐方式
flat 是否是 “扁平” 模式
checkable 是否可选择。
设为 true,则在 title 前方会多出一个可勾选的部分。
checked 描述分组框的选择状态(前提是 checkable 为 true)

TabWidget

标签页

在这里插入图片描述

属性:

属性 说明
tabPosition 标签页所在的位置,可选值:North(上方)、South(下方)、West(左侧)、East(右侧)
currentIndex 当前选中了第几个标签页(从 0 开始计算)
currentTabText 当前选中的标签页的文本
currentTabName 当前选中的标签页的名字
currentTabIcon 当前选中的标签页的图标
currentTabToolTip 当前选中的标签页的提示信息
tabsCloseable 标签页是否可以关闭
movable 标签页是否可以移动

信号:

属性 说明
currentChanged(int) 标签页切换时触发,参数是被点击选项卡编号
tabBarClicked(int) 点击选项卡标签条时触发,参数是被点击选项卡编号
tabBarDoubleClicked(int) 双击选项卡标签条时触发,参数是被点击选项卡编号
tabCloseRequest(int) 标签页关闭时触发,参数是被关闭选项卡编号

例如:

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

#include <QTreeWidgetItem>
#include <QDebug>
#include <QLabel>

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

    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_pushButtonAdd_clicked()
{
    int count = ui->tabWidget->count();

    QWidget* w = new QWidget();
    ui->tabWidget->addTab(w, QString("Tab ") + QString::number(count + 1));

    QLabel* label = new QLabel(w);
    label->setText("标签页 " + QString::number(count + 1));
    label->resize(100, 50);

    ui->tabWidget->setCurrentIndex(count);
}

void Widget::on_pushButtonDel_clicked()
{
    int index = ui->tabWidget->currentIndex();
    ui->tabWidget->removeTab(index);
}

void Widget::on_tabWidget_currentChanged(int index)
{
    qDebug() << "当前所在标签页为:" << index + 1;
}

注意:

  • 对于TabWidget中的每一个标签页,其都有对应的一个objectName,也就是其标签名
  • 如果要访问到这个标签页,使用ui->[objectName]即可

效果:

在这里插入图片描述


布局管理器

我们之前把控件放到界面上,都是靠“手动”的方式来布局的,这种方式是很不科学的

  • 手动布局的方式非常复杂,而且不精准
  • 无法对窗口大小进行自适应

此时就需要用到布局管理器

  • 垂直布局
  • 水平布局
  • 网格布局
  • 表单布局

注意:每个**Widget**只能设置一个布局管理器

  • 如果是在代码中创建layout,那么就只是创建了一个layout
  • 如果是在Qt Designer放置了一个layout,那么会先创建一个widget,再在widget里面创建layout

VBoxLayout

垂直布局管理器

属性

属性 说明
layoutLeftMargin 左侧边距
layoutRightMargin 右侧边距
layoutTopMargin 上方边距
layoutBottomMargin 下方边距
layoutSpacing 相邻元素之间的间距

VBoxLayout只用于布局,不提供信号

例如:

使用图形化界面的方式,使用垂直布局管理器:

  1. 先创建VerticalLayout,再放置元素:

    在这里插入图片描述

  2. 先放置元素,再设置垂直布局:

    在这里插入图片描述

查看效果:

在这里插入图片描述

通过代码的方式,使用垂直布局管理器:

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

#include <QVBoxLayout>
#include <QDebug>
#include <QPushButton>

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;
}

效果:

在这里插入图片描述

可以发现,如果用代码的方式,往窗口添加VBoxLayout,那么由于其不会创建额外的widget,因此此时的VBoxLayout就可以适配其父窗口(主窗口)的大小

但用Qt Designer进行创建,由于会产生额外的widget,因此此时的layout就不能适配主窗口大小


HBoxLayout

水平布局管理器

属性:

属性 说明
layoutLeftMargin 左侧边距
layoutRightMargin 右侧边距
layoutTopMargin 上方边距
layoutBottomMargin 下方边距
layoutSpacing 相邻元素之间的间距

HBoxLayoutVBoxLayout用法雷同,这里不过多赘述

这里来展示一个VBoxLayoutHBoxLayout嵌套的例子:

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

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QDebug>
#include <QPushButton>

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();
    this->setLayout(hlayout);

    // 将按钮添加到水平布局
    QPushButton* button3 = new QPushButton("按钮3");
    QPushButton* button4 = new QPushButton("按钮4");
    hlayout->addWidget(button3);
    hlayout->addWidget(button4);

    // 将水平布局管理器 添加到 垂直布局管理器中
    vlayout->addLayout(hlayout);
}

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

效果:

在这里插入图片描述


GridLayout

网格布局

属性:

属性 说明
layoutLeftMargin 左侧边距
layoutRightMargin 右侧边距
layoutTopMargin 上方边距
layoutBottomMargin 下方边距
layoutHorizontalSpacing 相邻元素水平方向间距
layoutVerticalSpacing 相邻元素垂直方向间距
layoutRowStretch 行方向拉伸系数
layoutColumnStretch 列方向拉伸系数

例如:

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

#include <QGridLayout>
#include <QDebug>
#include <QPushButton>

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

    QGridLayout* layout = new QGridLayout();
    this->setLayout(layout);

    QPushButton* button1 = new QPushButton("按钮1");
    QPushButton* button2 = new QPushButton("按钮2");
    QPushButton* button3 = new QPushButton("按钮3");
    QPushButton* button4 = new QPushButton("按钮4");

    // 网格布局
    layout->addWidget(button1, 0, 0);
    layout->addWidget(button2, 0, 1);
    layout->addWidget(button3, 1, 0);
    layout->addWidget(button4, 1, 1);

    // 水平布局
    layout->addWidget(button1, 0, 0);
    layout->addWidget(button2, 0, 1);
    layout->addWidget(button3, 0, 2);
    layout->addWidget(button4, 0, 3);

    // 垂直布局
    layout->addWidget(button1, 0, 0);
    layout->addWidget(button2, 1, 0);
    layout->addWidget(button3, 2, 0);
    layout->addWidget(button4, 3, 0);

    // 对角线布局
    layout->addWidget(button1, 0, 0);
    layout->addWidget(button2, 1, 1);
    layout->addWidget(button3, 2, 2);
    layout->addWidget(button4, 3, 3);
}

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

效果:

在这里插入图片描述

刚刚创建的布局管理器,控件的尺寸都是均等的

当需要创建出尺寸不同的控件的时候,就可以通过拉伸系数来设置。 拉伸系数就相当于设置控件之间尺寸的比例

例如:

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

    QGridLayout* layout = new QGridLayout();
    this->setLayout(layout);

    QPushButton* button1 = new QPushButton("按钮1");
    QPushButton* button2 = new QPushButton("按钮2");
    QPushButton* button3 = new QPushButton("按钮3");
    QPushButton* button4 = new QPushButton("按钮4");
    QPushButton* button5 = new QPushButton("按钮5");
    QPushButton* button6 = new QPushButton("按钮6");
    
    // 按钮大小自适应,水平方向和垂直方向的sizePolicy属性
    button1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    button2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    button3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    button4->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    button5->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    button6->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    // 网格布局 2 * 3
    layout->addWidget(button1, 0, 0);
    layout->addWidget(button2, 0, 1);
    layout->addWidget(button3, 0, 2);
    layout->addWidget(button4, 1, 0);
    layout->addWidget(button5, 1, 1);
    layout->addWidget(button6, 1, 2);

    // 设置垂直比例为 1 : 2
    layout->setRowStretch(0, 1);		// 第一行为 1
    layout->setRowStretch(1, 2);		// 第二行为 2

    // 设置水平比例为 1 : 2 : 3
    layout->setColumnStretch(0, 1);		// 第一列为 1
    layout->setColumnStretch(1, 2);		// 第二列为 2
    layout->setColumnStretch(2, 3);		// 第三列为 3
}

注意:

  • 如果拉伸系数设置为0,说明该行/列不参与拉伸,窗口大小为固定值

  • 关于QWidget属性 sizePolicy

    • QSizePolicy::Ignored : 忽略控件的尺寸,不对布局产生影响。

    • QSizePolicy::Minimum : 控件的最小尺寸为固定值,布局时不会小于该值。

    • QSizePolicy::Maximum : 控件的最大尺寸为固定值,布局时不会超过该值。

    • QSizePolicy::Preferred : 控件的理想尺寸为固定值,布局时会尽量接近该值。

    • QSizePolicy::Expanding : 控件的尺寸可以根据空间调整,尽可能占据更多空间。

    • QSizePolicy::Shrinking : 控件的尺寸可以根据空间调整,尽可能缩小以适应空间。

  • 按钮的水平布局是默认拉伸的,但是垂直布局不是,所以垂直布局不会受拉伸比例影响

  • 所以需要在拉伸之前设置按钮的sizePolicy属性

效果:

在这里插入图片描述


FormLayout

表单

FormLayout属于GridLayout的特殊情况,专门用于实现N2列的表单布局

例如

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

#include <QFormLayout>
#include <QDebug>
#include <QPushButton>
#include <QLabel>
#include <QLineEdit>

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

    QFormLayout* layout = new QFormLayout();
    this->setLayout(layout);

    layout->addRow(new QLabel("姓名"), new QLineEdit());
    layout->addRow(new QLabel("学号"), new QLineEdit());
    layout->addRow(nullptr, new QPushButton("提交"));

}

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

效果:

在这里插入图片描述


Spacer

使用布局管理器的时候,可能需要在控件之间添加一段空白,就可以使用QSpacerItem表示

属性:

属性 说明
width 宽度
height 高度
hData 水平方向的 sizePolicy
vData 垂直方向的 sizePolicy

例如:

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

    QHBoxLayout* layout = new QHBoxLayout();
    this->setLayout(layout);

    QPushButton* button1 = new QPushButton("按钮1");
    QPushButton* button2 = new QPushButton("按钮2");
    button1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    button2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    QSpacerItem* spacer = new QSpacerItem(200, 50, QSizePolicy::Expanding, QSizePolicy::Expanding);

    layout->addWidget(button1);
    layout->addSpacerItem(spacer);
    layout->addWidget(button2);
}

效果:

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到