GUI控件类
QWidget简介
所有界面组件类的直接或间接父类都是 QWidget。QWidget 的父类是 QObject 和 QPaintDevice,所以 QWidget 是多重继承的类。

QObject 支持元对象系统,其信号与槽机制为 GUI 编程中对象间通信提供了极大的便利。
QPaintDevice 是能使 QPainter 类在绘图设备上绘图的类。
我们可以新建一个Qt Widgets Application项目, 名字叫做01-QMainWindows
创建成功后,双击mainwindow.ui文件, 进入Designer界面。

- 红框1主要是控件区,包括常用的控件都罗列在这里。
- 绿框2主要是ui的布局区,可以拖动部件调整在布局中的位置,程序运行后会按照布局设计的样式展示。
- 黄框3主要是ui对象层级管理区,主要展示各个对象之间的层级关系。
- 篮筐4主要是属性编辑区,可以设计
我们在ui区可以看到MainWindow界面

我们观察QtDesigner界面左侧控件区, 会看到QWidget在Containers里,因为QWidget属于容器类型

大家可以直接拖动designer中的widget放入MainWindow界面里
然后在右侧的对象层级管理区能看到我们新增的widget

为了方便展示我们新增的widget,点击右侧对象层级管理中的widget,去右下方的属性管理器找到stylesheet样式表

点击右侧的小三角弹出编辑样式表,这个样式表就是设置控件样式的,包括颜色,大小等。我们添加背景颜色为绿色

点击ok保存,再次运行

这是最简单的利用Designer拖动实现界面创建的方式。
QWidget基本接口
显示和隐藏
show():显示窗口。hide():隐藏窗口。close():关闭窗口。
代码创建
我们也可通过代码创建一个widget,在main函数中将MainWindow展示逻辑去掉,替换成创建widget然后展示出来。
示例
展示一个窗口, 大家可以在main函数中创建这个QWidget,并展示出来,这是通过代码创建QWidget的方式。
cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget widget;
widget.show();
return a.exec();
}
大小和位置
resize(int width, int height):调整窗口大小。move(int x, int y):移动窗口到指定位置。setGeometry(int x, int y, int width, int height):设置窗口的几何属性。size():返回窗口的大小。pos():返回窗口的位置。
练习
我们重新设置widget大小为800*600
将窗口移动到(100,100)位置
并且将窗口展示出来
cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget widget;
//重新设置大小为800*600
widget.resize(800,600);
//移动到(100,100)位置
widget.move(100,100);
widget.show();
return a.exec();
}
添加资源文件
我们的一些界面会带有图标,为了添加图标,右键刚才创建的MainWindow项目弹出的菜单选择AddNew

选择Qt Resource

为资源文件命名为qrc

选择添加到项目

在项目目录里创建res文件夹,添加两个文件new.png和open.png


右键项目左侧目录数Resources下的qrc.qrc, 添加现有文件

在文件目录中选择我们刚才添加的图片文件

点击确定之后,可以看到项目结构目录下qrc文件下增加了图片资源

练习
将图片资源添加到项目中
使用资源
如果以后想要使用资源,可以右键对应的图片,在弹出的菜单选择copy path即可

代码中可以直接写这个路径作为资源路径进行加载
QMainWindow
QMainWindow是主窗口类,我们创建一个Qt Widgets Application项目,Qt Creator默认为我们生成的就是继承自QMainWindow的界面类并展示出来。
下图为QMainWindow的结构示意图

我们看下层级管理,

能看到几个控件
- menuBar 菜单栏
- mainToolBar 工具栏
- centralWidget 为中心控件
- widget为我们刚才添加的widget控件
- statusBar为状态栏
创建菜单
创建菜单可以通过ui创建,但是不够灵活,现在企业基本采用代码创建.
有时候MainWindow中没有菜单栏,可以通过ui添加,但不推荐,我们直接通过代码创建菜单栏,并将菜单栏设置到MainWindow中。
QMenuBar的构造函数接受一个QWidget作为其父节点
cpp
QMenuBar(QWidget *parent = nullptr)
MainWindow 设置菜单栏的接口
cpp
void QMainWindow::setMenuBar(QMenuBar *menuBar)
我们在MainWindow的构造函数中添加菜单栏
cpp
//设置窗口标题
this->setWindowTitle("myWindow");
//重设窗口大小
this->resize(1100,700);
//创建菜单栏
QMenuBar *menuBar = new QMenuBar(this);
//添加菜单栏到主窗口中
this->setMenuBar(menuBar);
QMenu构造函数有两个,可接受文本作为菜单的名字。
cpp
QMenu(QWidget *parent = nullptr)
QMenu(const QString &title, QWidget *parent = nullptr)
练习
接下来我们创建三个一级菜单(文件,编辑,构建)并添加到菜单栏里
cpp
//创建文件菜单
QMenu *menu1 = new QMenu("文件",this);
//创建编辑菜单
QMenu *menu2 = new QMenu("编辑",this);
//创建构建菜单
QMenu *menu3 = new QMenu("构建",this);
//将菜单添加到菜单栏
menuBar->addMenu(menu1);
menuBar->addMenu(menu2);
menuBar->addMenu(menu3);
再次运行可看到窗口里添加了菜单栏

添加菜单项
菜单项在Qt中叫做QAction, QAction包含三种构造参数
cpp
//接受一个参数,父节点
QAction(QObject *parent = nullptr)
//接受两个参数,菜单项的名字和其父节点
QAction(const QString &text, QObject *parent = nullptr)
//接受三个参数,菜单项的图标,菜单项的名字,父节点
QAction(const QIcon &icon, const QString &text, QObject *parent = nullptr)
QIcon的构造传入图片路径即可构造一个图标
cpp
QIcon(const QString &fileName)
QMenu添加菜单项的接口
cpp
void QMenu::addAction(Action *action)
QMenu可以为菜单项设置分割符
cpp
QAction *QMenu::addSeparator()
练习
在新建菜单下添加菜单项,名字为"新建文件或项目"
在新建菜单下添加菜单项,名字为"打开文件或项目"
在新建菜单下添加分隔符,分隔符下添加菜单项,名字为退出
可以配合前面添加到资源文件为菜单项设置图标
实现如下效果

答案
cpp
//创建菜单栏
QMenuBar *menuBar = new QMenuBar(this);
//添加菜单栏到主窗口中
this->setMenuBar(menuBar);
//创建文件菜单
QMenu *menu1 = new QMenu("文件",this);
//创建编辑菜单
QMenu *menu2 = new QMenu("编辑",this);
//创建构建菜单
QMenu *menu3 = new QMenu("构建",this);
//将菜单添加到菜单栏
menuBar->addMenu(menu1);
menuBar->addMenu(menu2);
menuBar->addMenu(menu3);
//创建新建菜单项
auto new_action = new QAction(QIcon(":/res/new.png"),"新建文件或项目",this);
//创建打开菜单项
auto open_action = new QAction(QIcon(":/res/open.png"),"打开文件或项目",this);
//创建退出菜单项
auto exit_action = new QAction("退出",this);
//添加新建菜单项
menu1->addAction(new_action);
//添加打开菜单项
menu1->addAction(open_action);
//添加分割符
menu1->addSeparator();
//添加退出菜单项
menu1->addAction(exit_action);
菜单项添加快捷键
我们可以通过QAction的函数setShortcut为菜单项添加快捷键
cpp
void setShortcut(const QKeySequence &shortcut)
QKeySequence构造函数接受按键组成的宏,比如快捷键Ctrl+N
cpp
action1->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_N));
练习
为新建文件菜单项添加快捷键Ctrl+N, 为打开文菜单项添加快捷键Ctrl+O
答案
cpp
//设置快捷键 ctrl + n
new_action->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_N));
//设置快捷键 ctrl + o
open_action->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_O));
菜单项添加触发槽函数
当菜单项被选中或者按下快捷键触发时会执行相应的逻辑,比如新建项目被点击后,执行新建项目的操作。
点击菜单项会触发菜单项发出triggered信号
cpp
[signal] void QAction::triggered(bool checked = false)
我们可以在MainWindow写一个槽函数,接受这个信号,并简单的弹出一个提示框做提示
QMessageBox
Qt 提示框的类为QMessageBox,QMessageBox提供了几个不同类型的对话框
信息消息框
cpp
QMessageBox::information(this, "Information", "This is an information message.");
警告消息框
cpp
QMessageBox::warning(this, "Warning", "This is a warning message.");
错误消息框
cpp
QMessageBox::critical(this, "Critical", "This is a critical error message.");
问题消息框
有时候提示框会提出问题,让用户选择确认还是取消,可以用问题消息框。
cpp
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "Question", "Do you want to continue?", QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
// User clicked Yes
} else {
// User clicked No
}
练习
为新建文件或项目这个菜单项添加点击后弹出信息消息框,提示"点击了创建文件或项目"

答案
MainWindow中添加槽函数
cpp
void MainWindow::slotNewFile()
{
QMessageBox::information(this,"通知","点击了新建文件或项目菜单");
}
在MainWindow的构造函数中连接新建菜单项和槽函数
cpp
//连接新建项目的菜单项的信号和mainwindow槽函数
connect(new_action, &QAction::triggered,this, &MainWindow::slotNewFile);
工具栏
添加工具栏
工具栏和菜单栏类似,如果ui文件中没有工具栏,我们可以用ui文件中的工具栏添加工具项。
否则我们需要先创建工具栏
cpp
//创建工具栏
auto tool_bar = new QToolBar(this);
//主窗口添加工具栏
this->addToolBar(tool_bar);
添加工具项
工具项和菜单项一样,都是QAction类型所以添加工具项很简单
添加工具项
cpp
//创建工具项
auto tool_new = new QAction(QIcon(":/res/new.png"),"新建",this);
auto tool_open = new QAction(QIcon(":/res/open.png"),"打开",this);
//添加工具项
tool_bar->addAction(tool_new);
tool_bar->addAction(tool_open);
//添加分割符号
tool_bar->addSeparator();
auto tool_exit = new QAction("退出",this);
//添加退出工具项
tool_bar->addAction(tool_exit);
状态栏
如果主窗口的ui里没有状态栏,需要创建。和之前菜单栏,工具栏类似,创建好状态栏再设置到主窗口中。
cpp
//创建状态栏
QStatusBar *status = new QStatusBar(this);
status->setObjectName("状态栏");
//设置不显示label的边框
status->setStyleSheet("QStatusBar::item{border: 0px}");
//主窗口添加状态栏
this->setStatusBar(status);
样式表也可以在代码中设置,我们之前是通过ui设置的。
状态栏可以设置标签,
cpp
//创建标签
QLabel *statusLabel = new QLabel("我是状态栏", this);
//状态栏添加信息
//显示在左侧,并且3秒后自动消失
status->showMessage("我在3秒后会消失", 3000);
//添加右侧标签(永久性)
status->addPermanentWidget(statusLabel);
练习
练习实现状态栏
组件划分
按照Qt Designer中提供的不同功能分区,组件大体包括
- 按钮类
-
- QPushButton
- QToolButton
- QRadioButton
- QCheckBox
- 输入类
-
- QLineEdit
- QTextEdit
- QPlainTextEdit
- QDateEdit
- QTimeEdit
- QSPinBox
- QComboBox
- 显示类
-
- QLabel
- QGraphicsView
- QProgressBar
- 容器类
-
- QWidget
- QScrollArea
- QFrame
- QListWidget
- QTableWidget
- QTreeWidget
大家可以在Designer中拖动上述组件感受下都是什么,因为QT组件过于庞杂,接下来按照分类挑选常用的介绍
按钮类
QPushButton
QPushButton是Qt提供的基础按钮类,可以设置按钮的文本,图标,快捷键等。
QPUshButton的三个构造函数
cpp
//一个参数指定父节点
QPushButton(QWidget *parent = nullptr);
//指定显示文本和父节点
QPushButton(const QString &text, QWidget *parent = nullptr);
//指定图标,显示文本,以及父节点
QPushButton(const QIcon &icon, const QString &text, QWidget *parent = nullptr);
我们通过代码的方式创建QPushButton并且显示在MainWindow上, 在MainWindow的构造函数里添加
cpp
//创建按钮,显示文本
QPushButton *button = new QPushButton("Click Me", this);
//为按钮设置图标
button->setIcon(QIcon(":/res/open.png"));
//设置按钮的位置和大小
button->setGeometry(100, 100, 100, 40);
setGeometry四个参数分别为按钮所在横坐标,按钮所在纵坐标,按钮宽度,按钮的高度等。
运行后可显示按钮

按钮被点击后会发出clicked信号
cpp
void clicked(bool checked = false)
练习
我们可以在MainWindow写一个槽函数slotBtnClick,捕获这个信号,然后弹出消息框显示"按钮被点击"

答案
为MainWindow类添加槽函数
cpp
void MainWindow::slotBtnClick()
{
QMessageBox::information(this,"通知","点击了按钮");
}
在MainWindow构造函数中连接按钮点击信号和MainWindow槽函数
cpp
connect(button, &QPushButton::clicked,this, &MainWindow::slotBtnClick);
QToolButton
QToolButton 是 Qt 框架中用于创建工具按钮的类。工具按钮通常用于工具栏或其他需要紧凑按钮布局的地方。与标准的 QPushButton 不同,QToolButton 通常更小,并且可以只显示图标、只显示文本或同时显示图标和文本。 使用时需包含QToolButton头文件
QToolButton的构造函数仅有一个参数
cpp
QToolButton(QWidget *parent = nullptr)
QToolButton同样支持设置现实的图标和文本
cpp
//创建一个工具按钮
QToolButton *toolButton = new QToolButton(this);
//设置图标
toolButton->setIcon(QIcon(":/res/new.png"));
//设置文本
toolButton->setText("Tool");
工具按钮可以设置几种显示样式
cpp
// 仅显示图标
toolButton->setToolButtonStyle(Qt::ToolButtonIconOnly);
// 仅显示文本
toolButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
// 图标在文本旁边
toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
// 图标在文本上方
toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
工具按钮可以放在工具栏里
cpp
//创建一个工具按钮
QToolButton *toolButton = new QToolButton(this);
//设置图标
toolButton->setIcon(QIcon(":/res/new.png"));
//设置文本
toolButton->setText("Tool");
//设置按钮样式,文本在图标旁边
toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
//工具栏添加按钮
tool_bar->addWidget(toolButton);
QToolButton按钮被点击后也会发出clicked信号。
练习
创建一个QToolButton,放在工具栏里,按钮样式为Qt::ToolButtonTextBesideIcon。
点击按钮后,弹出消息框显示"ToolButton被点击了"

答案
MainWindow构造函数里添加
cpp
//创建一个工具按钮
QToolButton *toolButton = new QToolButton(this);
//设置图标
toolButton->setIcon(QIcon(":/res/new.png"));
//设置文本
toolButton->setText("Tool");
//设置按钮样式,文本在图标旁边
toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
//按钮添加到工具栏上
tool_bar->addWidget(toolButton);
//连接按钮的点击信号
connect(toolButton,&QToolButton::clicked,this, &MainWindow::slotToolBtnClick);
MainWindow添加槽函数
cpp
void MainWindow::slotToolBtnClick()
{
QMessageBox::information(this,"通知","点击了工具按钮");
}
QRadioButton
QRadioButton为单选按钮,后续我们通过例子来演示和学习。这里大家可以拖动Designer中的QRadioButton到MainWindow.ui中,看看QRadioButton的样子

QCheckBox
QCheckBox为多选框, 大家可以添加到ui,启动程序看看样式

输入类控件
QLineEdit
QLineEdit主要是用来单行输入的控件,大家可以将一个QLineEdit拖动到ui里, 运行后看看效果

QLineEdit有几个信号介绍一下
cpp
//光标位置变化后发送信号
void cursorPositionChanged(int oldPos, int newPos)
//编辑完成后发送,失去光标时发送
void editingFinished()
//输入被拒绝时发出这个信号
void inputRejected()
//按下回车键后
void returnPressed()
//选择区域变化后
void selectionChanged()
//文本变化后
void textChanged(const QString &text)
//文本被编辑
void textEdited(const QString &text)
这些信号不用死记硬背,用到的时候查下assistant手册或者AI都可以,会用就行
QLineEdit也支持设置输入的模式

Normal 就是输入的内容正常显示

NoEcho就是输入的内容完全不显示,输入什么都是一片空白

Password就是以密码点的形式显示

PasswordEchoOnEdit就是输入的时候显示字符,失去焦点后变成密码点
在输入时是这样

失去焦点

通过setEchoMode可以设置输入模式
cpp
void setEchoMode(QLineEdit::EchoMode)
我们做个练习看看效果
练习
MainWindow上添加一个QLineEdit,设置输入模式为Password. 当输入完成后打印输入的密码
答案
mainwindow的构造函数里添加
cpp
//设置为密码输入模式
ui->lineEdit->setEchoMode(QLineEdit::Password);
//连接失去焦点信号和槽函数
connect(ui->lineEdit, &QLineEdit::editingFinished, [this](){
qDebug() << "editing Finished slot";
});
//连接按下回车信号和槽函数
connect(ui->lineEdit, &QLineEdit::returnPressed, [this](){
qDebug() << "returnPressed slot";
});
QTextEdit
文本编辑器,和QLineEdit一样,都是输入控件,QTextEdit支持多行输入。

QTextPlainEdit
QTextPlainEdit为纯文本编辑器,和QTextEdit功能类似,不做赘述
QDateEdit
QDateEdit是编辑日期的控件,拖动到ui运行可查看到

QDateEdit支持设置日期
cpp
QDateEdit *dateEdit = new QDateEdit(this);
dateEdit->setDate(QDate::currentDate()); // 设置为当前日期
获取日期
cpp
QDate selectedDate = dateEdit->date();
qDebug() << "Selected date:" << selectedDate.toString();
设置日期展示样式
cpp
dateEdit->setDisplayFormat("yyyy-MM-dd");
信号和槽
QDateEdit 提供了一些信号,例如 dateChanged 信号,当日期发生变化时会发出该信号。可以连接到槽函数来处理日期变化事件:
cpp
//连接日期变化信号
connect(dateEdit, &QDateEdit::dateChanged, this, &MainWindow::onDateChanged);
//日期变化的槽函数
void MainWindow::onDateChanged(const QDate &date) {
qDebug() << "New date selected:" << date.toString();
}
QTimeEdit
QTimeEdit和QDateEdit用法类似

QSpinBox
QSpinBox 是 Qt 框架中的一个控件,用于显示和编辑整数值。它提供了一个带有上下按钮的输入框,用户可以通过点击按钮或直接输入来更改数值。以下是 QSpinBox 的常见用法和示例。
基本用法
创建一个 QSpinBox 控件
cpp
QSpinBox *spinBox = new QSpinBox(this);
设置初始值
可以使用 setValue 方法来设置 QSpinBox 的初始值:
cpp
spinBox->setValue(10);
获取当前值
可以使用 value 方法来获取当前的数值:
cpp
int currentValue = spinBox->value();
qDebug() << "Current value:" << currentValue;
设置数值范围
可以使用 setMinimum 和 setMaximum 方法来设置允许的数值范围:
cpp
spinBox->setMinimum(0); // 最小值为0
spinBox->setMaximum(100); // 最大值为100
或者,使用 setRange 方法同时设置最小值和最大值:
cpp
spinBox->setRange(0, 100);
设置步长
可以使用 setSingleStep 方法来设置每次点击上下按钮时数值的变化步长:
cpp
spinBox->setSingleStep(5); // 每次增加或减少5
设置前缀和后缀
可以使用 setPrefix 和 setSuffix 方法来设置显示在数值前后的文本:
cpp
spinBox->setPrefix("$"); // 在数值前显示美元符号
spinBox->setSuffix(" kg"); // 在数值后显示单位
信号和槽
QSpinBox 提供了一些信号,例如 valueChanged 信号,当数值发生变化时会发出该信号。可以连接到槽函数来处理数值变化事件:
cpp
connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged(int)));
void MainWindow::onValueChanged(int value) {
qDebug() << "New value:" << value;
}
练习
把上面的例子串起来写一写
cpp
QSpinBox *spinBox = new QSpinBox(this);
spinBox->setRange(0, 100);
spinBox->setValue(10);
spinBox->setSingleStep(5);
spinBox->setPrefix("$");
spinBox->setSuffix(" kg");
spinBox->setGeometry(250,300,70,30);
总结
QSpinBox 是一个功能强大的控件,用于显示和编辑整数值。通过设置初始值、数值范围、步长、前缀和后缀等,可以灵活地定制 QSpinBox 的行为。结合信号和槽机制,可以轻松处理数值变化事件。这个控件在需要数值输入的应用程序中非常有用。
QComboBox
QComboBox 是 Qt 提供的一个下拉列表控件,允许用户从一个列表中选择一个条目。它可以包含文本条目,也可以包含更复杂的自定义项。
添加条目的接口
cpp
void addItem(const QString &text, const QVariant &userData = QVariant())
void addItem(const QIcon &icon, const QString &text, const QVariant &userData = QVariant())
userData字段很少用到,在传递自定义数据的时候会用到。我们添加条目时默认只写一个文本参数即可。
练习
创建并添加条目
cpp
//创建下拉列表控件
QComboBox *comboBox = new QComboBox(this);
//添加条目
comboBox->addItem("Option 1");
comboBox->addItem("Option 2");
comboBox->addItem("Option 3");
//移动到250,400位置
comboBox->move(250,400);

显示类
QLabel
QLabel 是 Qt 提供的用于显示文本或图像。它常用于展示静态内容,并且可以与其他控件组合使用来构建用户界面。
可以直接在构造函数里指定QLabel要显示的文本
cpp
explicit QLabel(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags());
explicit QLabel(const QString &text, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags());
例如:
cpp
// 创建一个简单的文本标签
QLabel *textLabel = new QLabel("Hello, QLabel!");
指定父窗口后,QLabel会自动添加到父窗口的(0,0)位置,可以通过move移动到指定的位置
cpp
QLabel *textLabel = new QLabel("Hello, QLabel!",this);
如果未设置父窗口,可调用addWidget将label加入指定窗口. 比如在MainWindow的构造函数中调用
cpp
this->addWidget(textLabel);
也可以通过setText更新QLabel显示的文本
cpp
textLabel->setText("Hello, Heima");
练习
主窗口设置一个下拉列表框和QLabel,下拉列表框有三个下拉选项(option1, option2, option3),
选择下拉条目后,label显示下拉列表框选择的内容.
提示:
QComboBox在条目有变化的时候会发出信号 currentTextChanged
答案
cpp
//创建下拉列表控件
QComboBox *comboBox = new QComboBox(this);
//添加条目
comboBox->addItem("Option 1");
comboBox->addItem("Option 2");
comboBox->addItem("Option 3");
//移动到250,400位置
comboBox->move(250,400);
//获取当前下拉框文本
auto text = comboBox->currentText();
QLabel *textLabel = new QLabel(this);
textLabel->move(250,500);
textLabel->setText(text);
//连接下拉框文本变化的信号
connect(comboBox,&QComboBox::currentTextChanged, [textLabel,comboBox](){
textLabel->setText(comboBox->currentText());
});
QGraphicsView
QGraphicsView 是 Qt 框架中的一个类,用于显示和交互 QGraphicsScene 中的内容。它是 Qt 的图形视图框架的一部分,该框架提供了一种灵活且高效的方法来管理和显示复杂的 2D 图形.QGraphicsView 提供了一个视口(viewport),通过这个视口可以查看 QGraphicsScene 的一部分。视口可以移动和缩放,从而查看场景的不同部分。之后在绘图的时候给大家演示,这个目前仅作了解
QProgressBar
QProgressBar 是 Qt 框架中的一个小部件类,用于显示任务进度的图形化表示。它通常用于展示任务的完成百分比,给用户提供任务进度的视觉反馈。QProgressBar 的使用非常简单且直观,适用于各种需要显示进度的场景,例如文件下载、数据处理等
设置范围
可以通过 setRange(int minimum, int maximum) 方法设置进度条的最小值和最大值。默认情况下,最小值为 0,最大值为 100。
设置当前值
可以通过 setValue(int value) 方法设置当前的进度值。进度值在最小值和最大值之间变化。
文本显示
QProgressBar 可以在进度条上显示文本,例如完成百分比。可以通过 setFormat(const QString &format) 方法自定义显示的文本格式。
练习
主界面拖动一个按钮和进度条。进度条初始值为0,范围为0到100.
当点击按钮后,定时更新进度条,每100ms进度条的数值+1。进度条满后停止计时。
提示:QTimer为定时器类,大家锻炼下查阅assistant的能力
QTimer有start函数开启定时器,参数为设置的检测时间间隔,单位为ms
QTimer信号timout会在每次时间间隔达到时发送。
QTimer有stop函数停止定时器

答案
ui中拖动按钮和进度条,按钮名称修改为timerBtn, 进度条修改为timerProgress
cpp
//定义定时器
auto timer = new QTimer(this);
// 绑定定时器检测间隔超时信号和回调函数
connect(timer, &QTimer::timeout, [this, timer](){
//判断进度条是否满格
if(ui->timerProgress->value() >= 100){
timer->stop();
return;
}
//更新进度条数值
ui->timerProgress->setValue(ui->timerProgress->value()+1);
});
//连接点击信号
connect(ui->timerBtn,&QPushButton::clicked,[this,timer](){
//开始定时器,每个100ms进行检测一次
timer->start(100);
});
还有一些组件比如Slider,以后用到了再查文档即可,QT提供的控件库太丰富了,学习常用的先入手。
布局
当我们拖动一个新的控件到ui文件中,需要关注ui文件中其他控件的位置,防止两个控件重叠。
有时,随着界面调整,按照位置设置好的控件不会随着界面拉伸而改变。
比如我们拖动MainWindow界面,控件并没有随着MainWindow的拉伸做调整

对于这种情况,我们可以采用Layout布局解决。
布局分为四种,有垂直布局,网格布局,水平布局,表单布局。
我们先看水平布局, 布局中的所有控件水平排列

垂直布局, 布局中的所有控件垂直排列

网格布局,布局中的所有控件按照网格的方式排列,有的占据多行或者多列。

表单布局,可以方便的完成表单样式,比如我们一些登录注册信息ui可以用这个布局。

设置布局整体有三种方式:
- 在ui中选中窗口,将窗口调整为垂直布局,网格布局,或者水平布局的一种
- 拖动一种布局放入ui,再将其他控件放入布局中。
- 写代码添加布局,然后再写代码将控件加入布局中。
先介绍第一种,我们双击mainwindow.ui,打开QT designer , 选中右侧对象层级表中centralWidget,

再点击工具栏中网格布局图标

将MainWindow的centralwidget设置为网格布局,可以在ui布局中看到控件整体布局变成了网格模式

运行起来,仍有部分控件散乱排布,是因为我们没有将控件加入布局,直接添加到mainwindow导致的,接下来我们用代码的方式将这些控件加入布局.
因为我们将centralwidget修改为网格布局,所以ui->centralWidget->layout()可以直接访问这个网格布局
cpp
//创建按钮,显示文本
QPushButton *button = new QPushButton("Click Me", this);
//为按钮设置图标
button->setIcon(QIcon(":/res/open.png"));
//设置按钮的位置和大小
button->setGeometry(100, 100, 100, 40);
connect(button, &QPushButton::clicked,
this, &MainWindow::slotBtnClick);
ui->centralWidget->layout()->addWidget(button);
依次类推,大家可以将其他的控件都加入布局,看到i的效果就是

当我们缩放或者拉伸,可以看到控件会随着拉伸变化。
我们在对象管理器中选中centralWidget,观察右下方属性管理器

红色框中 layoutHorizontalSpacing表示控件之间的水平间距
layoutVerticalSpacing表示控件之间的垂直间距
layoutRowStretch表示垂直拉伸比例,当布局被拉伸后,里面的控件垂直拉伸的比例如何。
layoutColumnStretch表示水平拉伸比例,当布局被拉伸后,里面的控件水平拉伸的比例如何。
如果是水平布局或i这垂直布局,间距用layoutSpacing表示,拉伸比用layoutStretch表示。
代码方式创建布局
布局类型:
- 水平布局QHBoxLayout
- 垂直布局QVBoxLayout
- 网格布局QGridLayout
向布局中添加widget控件,第一个参数是要添加的控件,第二个参数是该控件的拉伸比例,不设置默认等比拉伸
cpp
void addWidget(QWidget *, int stretch = 0, Qt::Alignment alignment = Qt::Alignment());
假设水平布局中有两个控件A和B,A的拉伸比例为2,B的拉伸比例为1,那么当界面被水平拉伸时,控件A宽度的增长速度是B的2倍

拉伸后

可以看到拉伸后A的宽度是B的2倍
练习
我们创建水平布局,封装到函数SetHorizontalLayout中
cpp
void MainWindow::SetHorizontalLayout()
{
//添加水平布局
auto layout = new QHBoxLayout(this);
//创建两个按钮
auto btn1 = new QPushButton("btn1",this);
auto btn2 = new QPushButton("btn2",this);
//将按钮加入到layout中
layout->addWidget(btn1);
layout->addWidget(btn2);
//将centralwidget布局设置为水平布局
ui->centralWidget->setLayout(layout);
}
在MainWindow的构造函数中调用,再启动程序能看到按钮并排排列了。

创建垂直布局
cpp
void MainWindow::SetVerticalLayout()
{
//添加垂直布局
auto layout = new QVBoxLayout(this);
//添加两个按钮
auto btn1 = new QPushButton("btn1",this);
auto btn2 = new QPushButton("btn2",this);
//将按钮加入布局
layout->addWidget(btn1);
layout->addWidget(btn2);
//将centralwidget布局设置为垂直布局
ui->centralWidget->setLayout(layout);
}

创建网格布局
cpp
void MainWindow::SetGridLayout()
{
//添加网格布局
auto layout = new QGridLayout(this);
//创建几个按钮
auto btn1 = new QPushButton("btn1",this);
auto btn2 = new QPushButton("btn2", this);
auto btn3 = new QPushButton("btn3", this);
auto btn4 = new QPushButton("btn4", this);
auto btn5 = new QPushButton("btn5", this);
//btn1 放在第一行第一列,占一行一列
layout->addWidget(btn1,0,0,1,1);
//btn2 放在第二行第一列,占一行两列
layout->addWidget(btn2,1,0,1,2);
//btn3 放在第二行第三列,占一行一列
layout->addWidget(btn3,1,2,1,1);
//btn4 放在第三行第一列,占两行一列
layout->addWidget(btn4,2,0,2,1);
//btn5 放在第四行第二列,占一行一列
layout->addWidget(btn5,3,1,1,1);
//将centralwidget设置为网格布局
this->centralWidget()->setLayout(layout);
}

因为整个页面高度很大,所以按钮布局看起来高度不一致。可以拉伸页面,将高度缩小为最小,就能看到btn4实际是占用了两行。
添加弹簧
QT提供了弹簧控件,可以通过Designer拖动到ui中,Horizontal Spacer是水平弹簧,Vertical Spacer是垂直弹簧
弹簧的作用就是压缩空间,让控件达到紧凑排布的效果。

也可写代码创建,写代码创建的弹簧是不分垂直还是水平的,取决于将弹簧添加到什么布局里,将弹簧加到水平布局里就是水平弹簧,将弹簧加到垂直布局里就是垂直布局

QSpacerItem构造函数
cpp
QSpacerItem(int w, int h,QSizePolicy::Policy hData = QSizePolicy::Minimum,
QSizePolicy::Policy vData = QSizePolicy::Minimum)
第一个参数为弹簧的宽,第二个参数为弹簧的高,第三个参数为弹簧的水平策略,第四个参数为弹簧的垂直策略。
常见的 QSizePolicy策略
- Fixed :
小部件的大小是固定的,不能扩展或收缩。 - Minimum :
小部件可以收缩到最小大小,但不能扩展。 - Maximum :
小部件可以扩展到最大大小,但不能收缩。 - Preferred :
小部件可以根据其建议的大小进行调整,但不会强制扩展或收缩。 - Expanding :
小部件可以扩展以填充可用空间。 - MinimumExpanding :
小部件可以收缩到最小大小,但也可以扩展以填充可用空间。 - Ignored :
小部件的大小策略被忽略,布局管理器将不会考虑它的大小。
不用死记硬背,最常用的就是好Expanding和Fixed,其余用到了再查文档。
将弹簧加入布局的函数为
cpp
void addSpacerItem(QSpacerItem *spacerItem);
练习
写代码在水平布局中插入一个弹簧,将按钮挤压到最左侧。
cpp
void MainWindow::SetHorizontalLayout()
{
//添加水平布局
auto layout = new QHBoxLayout(this);
//创建两个按钮
auto btn1 = new QPushButton("btn1",this);
auto btn2 = new QPushButton("btn2",this);
//将按钮加入到layout中
layout->addWidget(btn1);
layout->addWidget(btn2);
//创建水平弹簧,水平为扩展策略,垂直为可扩充到最大20像素
auto h_spacer = new QSpacerItem(40,20,
QSizePolicy::Expanding,QSizePolicy::Maximum);
//布局里添加弹簧
layout->addSpacerItem(h_spacer);
//将centralwidget布局设置为水平布局
ui->centralWidget->setLayout(layout);
}
效果

垂直布局也是这么设置,添加的弹簧默认为垂直弹簧。
那么网格布局添加弹簧需要指定弹簧所在的行列,添加的函数变成了addItem
cpp
void addItem(QLayoutItem *item, int row, int column, int rowSpan = 1,
int columnSpan = 1, Qt::Alignment = Qt::Alignment());
我们基于前面创建的网格布局代码,添加弹簧
cpp
//创建垂直弹簧,水平策略为Maximum,垂直方向为Expanding
auto v_spacer = new QSpacerItem(40,20,
QSizePolicy::Maximum,QSizePolicy::Expanding);
//创建水平弹簧,水平策略为Expanding,垂直策略为Maximum
auto h_spacer = new QSpacerItem(40,20,
QSizePolicy::Expanding, QSizePolicy::Maximum);
//加入垂直弹簧,放在第五行第1列
layout->addItem(v_spacer,4,0);
//加入水平弹簧,放在第四行第3列
layout->addItem(h_spacer,3,2);
//将centralwidget设置为网格布局
this->centralWidget()->setLayout(layout);
效果

布局边界
我们将一个控件或者多个控件放入布局后,它们与布局边界之间的距离叫做边界(Margin)

可通过Designer中对布局设置编剧

也可以通过代码设置
cpp
//设置边距
void setContentsMargins(int left, int top, int right, int bottom);
练习
将之前的水平布局边距分别设置为左边距20,上边距30,右边距40,底边距50的样式
答案
cpp
layout->setContentsMargins(20,30,40,50);
QListWidget
QListWidget 是 Qt 提供的一个方便的列表小部件

我们打开ui布局管理器,拖动一个QListWidget放入mainwindow.ui中

右键这个QListWidget,选择编辑项目

点击加号创建项目,项目名字可以修改

保存ui运行一下,看看效果

综合练习
实现如下界面,Profession下拉列表可以用QListWidget
