当前位置: 首页 > news >正文

Qt——常用Widget(控件)

常用控件 Widget

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

文章目录

  • 常用控件 Widget
  • 按钮类控件
    • QPushButton
    • QRadioButton
    • QCheckBox
  • 显示类控件
    • QLabel
      • 初识事件
    • LCD Number
    • ProgressBar
    • CalendarWidget
  • 输入类控件
    • LineEdit
    • TextEdit
    • ComboBox
    • SpinBox & DoubleSpinBox
    • Dial
    • Slider
  • 多元素控件
    • ListWidget
    • TableWidget
    • TreeWidget
  • 容器类控件
    • GroupBox
    • TabWidget
  • 布局管理器
    • VBoxLayout
    • HBoxLayout
    • GridLayout
    • FormLayout
    • Spacer

按钮类控件

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

核心的属性:

属性说明
textQLabel 中的文本
textFormat文本的格式.
- Qt::PlainText 纯文本
- Qt::RichText 富文本(支持 html 标签)
- Qt::MarkdownText markdown 格式
- Qt::AutoText 根据文本内容自动决定文本格式.
pixmapQLabel 内部包含的图片.
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_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic: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);	// 30pxui->label_3->setText("aaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaa");// 设置边距ui->label_4->setWordWrap(true);ui->label_4->setMargin(50);	// 50pxui->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是一个专门用来显示数字的控件。类似于”老式计算机“

在这里插入图片描述

相关属性:

属性说明
intValueQLCDNumber 显示的数字值(int)。
valueQLCDNumber 显示的数字值(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 * 3layout->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 : 2layout->setRowStretch(0, 1);		// 第一行为 1layout->setRowStretch(1, 2);		// 第二行为 2// 设置水平比例为 1 : 2 : 3layout->setColumnStretch(0, 1);		// 第一列为 1layout->setColumnStretch(1, 2);		// 第二列为 2layout->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);
}

效果:

在这里插入图片描述

http://www.lryc.cn/news/622406.html

相关文章:

  • 数据结构初阶(17)排序算法——非比较排序、排序算法总结
  • Git、JSON、MQTT
  • 【Javaweb学习|黑马笔记|Day1】初识,入门网页,HTML-CSS|常见的标签和样式|标题排版和样式、正文排版和样式
  • 混凝土抗压强度预测:基于机器学习的全流程实战解析​
  • flume实战:从零配置到启动运行的完整指南
  • 【嵌入式C语言】五
  • 模型输出参数和量化参数一文详解!!
  • Eclipse:关闭项目
  • 腾讯位置商业授权微信小程序逆地址解析(坐标位置描述)
  • 【LeetCode 热题 100】121. 买卖股票的最佳时机
  • OpenZeppelin Contracts 架构分层分析
  • 再回C的进制转换--负数
  • python的美食交流社区系统
  • 【Spring Cloud 微服务】1.Hystrix断路器
  • 两幅美国国旗版权挂钩专利发起跨境诉讼
  • 列式存储与行式存储:核心区别、优缺点及代表数据库
  • Spring Boot 静态函数无法自动注入 Bean?深入解析与解决方案
  • 上下文块嵌入(contextualized-chunk-embeddings)
  • Mybatis简单练习注解sql和配置文件sql+注解形式加载+配置文件加载
  • 图像识别控制技术(Sikuli)深度解析:原理、应用与商业化前景
  • System V通信机制
  • Web攻防-大模型应用LLM安全提示词注入不安全输出代码注入直接间接数据投毒
  • Go语言 time 包详解:从基础到实战
  • Vue模板引用(Template Refs)全解析1
  • 介绍大根堆小根堆
  • 命令模式C++
  • 【DSP28335 事件驱动】唤醒沉睡的 CPU:外部中断 (XINT) 实战
  • AI - MCP 协议(一)
  • 备忘录模式C++
  • 线性代数 · 直观理解矩阵 | 空间变换 / 特征值 / 特征向量