QT的常用控件
- 一.按钮类控件
- 1.1 Push Button
- 代码示例: 带有图标的按钮
- 代码示例: 带有快捷键的按钮
- 代码示例: 按钮的重复触发
- 1.2 Radio Button
- 代码示例: 选择性别
- 代码示例: click, press, release, toggled 的区别
- 代码示例: 单选框分组
- 1.3 Check Box
- 代码示例: 获取复选按钮的取值
- 二.显示类控件
- 2.1Label
- 代码示例: 显示不同格式的文本
- 代码示例: 显示图片
- 代码示例: 文本对齐, 自动换行, 缩进, 边距
- 编写 widget.cpp, 给这四个 label 设置属性.
- 代码示例: 设置伙伴
- 2.2 LCD Number
- 代码示例 倒计时
- 2.3 ProgressBar
- 代码示例 设置进度条按时间增长
- 代码示例 创建⼀个红色的进度条
- 2.3 Calendar Widget
- 代码示例: 获取选中的日期
- 三.输入类控件
- 3.1 Line Edit
- 代码示例: 录入个人信息
- 代码示例: 使用正则表达式验证输入框的数据
- 代码示例: 验证两次输入的密码⼀致
- 代码示例: 切换显示密码
- 3.2 TextEdit
- 代码示例: 获取多行输⼊框的内容
- 代码示例: 验证输⼊框的各种信号
- 3.3 Combo Box
- 核心属性
- 核心方法
- 核心信号
- 代码示例: 使用下拉框模拟⻨当劳点餐
- 代码示例: 从文件中加载下拉框的选项
- 3.4 spin Box
- 核心信号
- 代码示例: 调整⻨当劳购物车中的份数
- 3.5 Date Edit & Time Edit
- 核心信号
- 代码示例: 实现日期计算器
- 3.6 Dial
- 核心属性
- 核心信号
- 代码示例: 调整窗口透明度
- 3.6 Slider
- 核心属性
- 核心信号
- 代码⽰例: 调整窗⼝大小
- 代码示例: 通过⾃定义快捷键调整滑动条位置
- 四.多元素控件
- 4.1 List Widget
- 核心属性
- 核心方法
- 核心信号
- 代码示例: 使用 ListWidget
- 4.2 Table Widget
- `QTableWidget` 核心方法
- 代码示例: 使用 QTableWidget
- 4.3 Tree Widget
- QTreeWidget 核心方法
- QTreeWidget 核心信号
- QTreeWidgetItem 核心属性
- QTreeWidgetItem 核心方法
- 代码示例: 使用 QTreeWidget
- 五.容器类控件
- 5.1Group Box
- 核心属性
- 代码⽰例: 给麦当劳案例加上分组框
- 5.2Tab Widget
- 核心属性
- 核心信号
- 代码示例: 使用标签页管理多组控件
- 六.布局管理器
- 6.1垂直布局
- 核心属性
- 代码示例: 使用 QVBoxLayout 管理多个控件.
- 代码示例: 创建三个 QVBoxLayout
- 6.2水平布局
- 核心属性
- 代码示例: 使用 QHBoxLayout 管理控件
- 代码示例: 嵌套的 layout
- 6.3网格布局
- 核心属性
- 代码示例: 使用 QGridLayout 管理元素
- 代码示例: 设置 QGridLayout 中元素的大小比例.
- 代码示例: 设置垂直方向的拉伸系数
- 6.4表单布局
- 代码示例: 使用 QFormLayout 创建表单.
- 6.5Spacer
- 核心属性
- 代码示例: 创建⼀组左右排列的按钮.
一.按钮类控件
1.1 Push Button
使用 QPushButton 表示⼀个按钮.
QPushButton 继承自QAbstractButton . 这个类是⼀个抽象类. 是其他按钮的父类.
在 Qt Designer 中也能够看到这里的继承关系.
QAbstractButton 中, 和 QPushButton 相关性较大的属性
属性 | 说明 |
---|---|
text | 文本 |
icon | 按钮中的图标 |
shortCut | 按钮对应的快捷键 |
autoRepeat | 按钮是否会重复触发. 当鼠标左键按住不放时;如果设为 true, 则会持续产生鼠标点击事件;如果设为 false, 则必须释放鼠标, 再次按下鼠标时才能产生点击事件. |
autoRepeatDelay | 重复触发的延时时间. 按住按钮多久之后, 开始重复触发 |
autoRepeatInterval | 重复触发的周期. |
注意
:
- QAbstractButton 作为 QWidget 的子类, 当然也继承了 QWidget 的属性. 上面介绍的 QWidget 里的各种属性用法, 对于 QAbstractButton 同样适用. 因此表格仅列出 QAbstractButton 独有的属性
- Qt 的 api 设计风格是非常清晰的. 此处列出的属性都是可以 获取 和 设置 的. 例如, 使用 text() 获取按钮⽂本; 使用 setText() 设置⽂本.
代码示例: 带有图标的按钮
(1) 创建 resource.qrc 文件, 并导入图片
(2)在界面上创建⼀个 按钮
(3)修改 widget.cpp, 给按钮设置图标.
#include "widget.h"
#include "ui_widget.h"
#include<QIcon>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QIcon ico(":/asd.png");
ui->pushButton->setIcon(ico);
ui->pushButton->setIconSize(QSize(50,50));
}
Widget::~Widget()
{
delete ui;
}
代码效果图
代码示例: 带有快捷键的按钮
-
在界面中拖五个按钮.
-
创建 resource.qrc , 并导⼊ 5 个图片
-
修改 widget.cpp, 设置图标资源和快捷键,
#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>
#include<QDebug>
#include<QIcon>
#include<QPixmap>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QIcon icon(":/up.png");
ui->pushButton_up->setIcon(icon);//给按钮设置图标
QIcon icon1(":/down.png");
ui->pushButton_down->setIcon(icon1);
QIcon icon2(":/left.png");
ui->pushButton_left->setIcon(icon2);
QIcon icon3(":/right.png");
ui->pushButton_right->setIcon(icon3);
ui->pushButton_up->setShortcut(QKeySequence(Qt::Key_W+Qt::CTRL));//给按钮设置快捷键
ui->pushButton_down->setShortcut(QKeySequence("s"));
ui->pushButton_left->setShortcut(QKeySequence(Qt::Key_A));
ui->pushButton_right->setShortcut(QKeySequence(Qt::Key_D));
QIcon ico(":/up.png");
this->setWindowIcon(ico);//设置窗口图标
QPixmap pix(":/up.png");
pix =pix.scaled(64,64);//设置尺寸
QCursor cur(pix,2,2);//设置鼠标样式
this->setCursor(cur);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_up_clicked()
{
QRect ret = ui->textEdit->geometry();
ui->textEdit->setGeometry(ret.x(),ret.y()-5,ret.width(),ret.height());
qDebug()<<"up";
}
void Widget::on_pushButton_right_clicked()
{
QRect ret = ui->textEdit->geometry();
ui->textEdit->setGeometry(ret.x()+5,ret.y(),ret.width(),ret.height());//获取坐标
qDebug()<<"right";
}
void Widget::on_pushButton_left_clicked()
{
QRect ret = ui->textEdit->geometry();
ui->textEdit->setGeometry(ret.x()-5,ret.y(),ret.width(),ret.height());
qDebug()<<"left";
}
void Widget::on_pushButton_down_clicked()
{
QRect ret = ui->textEdit->geometry();
ui->textEdit->setGeometry(ret.x(),ret.y()+5,ret.width(),ret.height());
qDebug()<<"down";
}
代码示例: 按钮的重复触发
在上述案例中, 按住快捷键, 是可以进行重复触发的. 但是鼠标点击则不能.使用setAutoRepeat
即可
通过下述代码即可
ui->pushButton_up->setAutoRepeat(true);
ui->pushButton_down->setAutoRepeat(true);
ui->pushButton_left->setAutoRepeat(true);
ui->pushButton_right->setAutoRepeat(true);
1.2 Radio Button
QRadioButton 是单选按钮. 可以让我们在多个选项中选择⼀个.
作为 QAbstractButton 和 QWidget 的子类, 上面介绍的属性和用法, 对于 QRadioButton同样适用.
QAbstractButton 中和 QRadioButton 关系较⼤的属性
属性 | 说明 |
---|---|
checkable | 是否能选中 |
checked | 是否已经被选中. checkable 是 checked 的前提条件. |
autoExclusive | 选中⼀个按钮之后是否会取消其他按钮的选中.对于 QRadioButton 来说默认就是排他的. |
代码示例: 选择性别
在界面上创建⼀个 label, 和 3 个 单选按钮
void Widget::on_radioButton_male_clicked()
{
ui->label->setText("你选择的性别为: 男");
}
void Widget::on_radioButton_female_clicked()
{
ui->label->setText("你选择的性别为: ⼥");
}
void Widget::on_radioButton_other_clicked()
{
ui->label->setText("你选择的性别为: 其他");
}
当前代码中, 如果程序启动, 则不会选择任何选项
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置默认选中该按钮
ui->radioButton_male->setChecked(true);
ui->label->setText("你选择的性别为: 男");
}
当前代码中, 也可以禁⽤ “其他” 被选中.
// 禁⽤ other 选项
ui->radioButton_other->setCheckable(false);
代码示例: click, press, release, toggled 的区别
- clicked 表示一次 “点击”
- pressed 表示鼠标 “按下”
- released 表示鼠标 “释放”
- toggled 表示按钮状态切换.
- 在界面上创建四个单选按钮
(2)给 1 创建 clicked 槽函数, 给 2 创建 pressed 槽函数, 给 3 创建 released 槽函数,给 4 创建 toggled 槽函数.
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_radioButton_clicked(bool checked)
{
qDebug()<<"clicked"<<checked;
}
void Widget::on_radioButton_2_pressed()
{
qDebug()<<"pressed";
}
void Widget::on_radioButton_3_released()
{
qDebug()<<"relesed";
}
void Widget::on_radioButton_4_toggled(bool checked)
{
qDebug()<<"toggled"<<checked;
}
(3)运行程序, 可以看到
clicked
是⼀次鼠标按下+鼠标释放触发的.pressed
是鼠标按下触发的released
是鼠标释放触发的.toggled
是 checked 属性改变时触发的.
代码示例: 单选框分组
在界面上创建 6 个单选框, ⽤来模拟麦当劳点餐界面
此时直接运行程序, 可以看到, 这六QRadioButton 之间都是排他的.
我们希望每⼀组内部来控制排他, 但是组和组之间不能排他.
引入 QButtonGroup 进行分组.
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建三个 QButtonGroup
QButtonGroup* group1 = new QButtonGroup(this);
QButtonGroup* group2 = new QButtonGroup(this);
QButtonGroup* group3 = new QButtonGroup(this);
// 把 QRadioButton 两两⼀组, 放到三个 QButtonGroup 中.
group1->addButton(ui->radioButton);
group1->addButton(ui->radioButton_2);
group2->addButton(ui->radioButton_3);
group2->addButton(ui->radioButton_4);
group3->addButton(ui->radioButton_5);
group3->addButton(ui->radioButton_6);
}
1.3 Check Box
QCheckBox 表示复选按钮. 可以允许选中多个和 QCheckBox 最相关的属性也是 checkable checked , 都是继承自QAbstractButton
代码示例: 获取复选按钮的取值
在界面上创建 三个复选按钮, 和⼀个普通按钮.
给 pushButton 添加 slot 函数
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
QString result = "今天你的安排是:";
if(ui->checkBox_ls->isChecked())
{
result += ui->checkBox_ls->text() + " ";
}
if(ui->checkBox_paly->isChecked())
{
result += ui->checkBox_paly->text()+ " ";
}
if(ui->checkBox_work->isChecked())
{
result += ui->checkBox_work->text()+ " ";
}
ui->label->setText(result);
}
二.显示类控件
2.1Label
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 就会被选中. |
代码示例: 显示不同格式的文本
在界⾯上创建三个 QLabel
#include "widget.h"
#include "ui_widget.h"
#include<QLabel>
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->setText("富文本");
ui->label_3->setTextFormat(Qt::MarkdownText);//markdown
ui->label_3->setText("## 这是⼀段 markdown ⽂本");
}
Widget::~Widget()
{
delete ui;
}
代码示例: 显示图片
虽然 QPushButton 也可以通过设置图标的方式设置图片, 但是并非是⼀个好的选择. 更多的时候还是希望通过 QLabel 来作为⼀个更单纯的显示图片的方式.
在界面上创建⼀个 QLabel, objectName 为 label
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPixmap>
#include<QDebug>
#include<QResizeEvent>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QRect windowrect = this->geometry();
//设置label与窗口一样大
ui->label->setGeometry(0,0,windowrect.width(),windowrect.height());
QPixmap pix(":/Payara.png");
ui->label->setPixmap(pix);//将图片设置到label中
ui->label->setScaledContents(true); // 设置内容伸缩
}
Widget::~Widget()
{
delete ui;
}
//从写父类 触发resize事件 相当于回调函数
void Widget::resizeEvent(QResizeEvent *event)
{
qDebug()<<event->size();
//让label和窗口的大小始终一致
ui->label->setGeometry(0,0,event->size().width(),event->size().height());
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
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;
};
#endif // WIDGET_H
代码示例: 文本对齐, 自动换行, 缩进, 边距
创建四个 label, objectName 分别是 label 到 label_4并且在 QFrame 中设置 frameShape 为 Box (设置边框之后看起来会更清晰⼀些)
QFrame 是 QLabel 的父类. 其中 frameShape 属性用来设置边框性质.
- QFrame::Box :矩形边框
- QFrame::Panel :带有可点击区域的面板边框
- QFrame::WinPanel :Windows风格的边框
- QFrame::HLine :水平线边框
- QFrame::VLine :垂直线边框
- QFrame::StyledPanel :带有可点击区域的面板边框,但样式取决于窗口主题
编写 widget.cpp, 给这四个 label 设置属性.
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//在构造函数中,给label设置不同的属性
ui->label->setText("这是一段文本");
ui->label->setAlignment(Qt::AlignCenter|Qt::AlignHCenter);//垂直和水平居中
ui->label_2->setText("这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本");
ui->label_2->setWordWrap(true);//自动换行
ui->label_3->setText("这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本");
ui->label_3->setWordWrap(true);
ui->label_3->setIndent(50);//设置缩进 50px缩进
ui->label_4->setText("这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本,这是一段很长的文本");
ui->label_4->setMargin(50); //设置边距
}
Widget::~Widget()
{
delete ui;
}
代码示例: 设置伙伴
创建两个 label 和 两个 radioButton
此处把 label 中的文本设置为 “快捷键 &A” 这样的形式.
其中 & 后面跟着的字符, 就是快捷键.
可以通过 alt + A 的方式来触发该快捷键.
编写 widget.cpp, 设置 buddy 属性
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置label 和radio button伙伴关系
ui->label->setBuddy(ui->radioButton);
ui->label_2->setBuddy(ui->radioButton_2);
// Qlabel中可以指定快捷键 &A 通过alt+A触发快捷键
}
Widget::~Widget()
{
delete ui;
}
) 运行程序, 可以看到, 按下快捷键 alt + a
或者 alt + b,
即可选中对应的选项.
2.2 LCD Number
QLCDNumer 是⼀个专门用来显示数字的控件
核心属性
属性 | 说明 |
---|---|
intValue | QLCDNumber 显示的数字值(int). |
value | QLCDNumber 显示的数字值(double). |
和 intValue 是联动的. | |
digitCount | 显示几位数字 |
mode | 数字显示形式. QLCDNumber::Dec :⼗进制模式,显示常规的⼗进制数字 |
segmentStyle | 设置显示风格. QLCDNumber::Flat :平面的显示风格,数字呈现在⼀个平坦的表面上。QLCDNumber::Outline :轮廓显示风格,数字具有清晰的轮廓和阴影效果。QLCDNumber::Filled :填充显示风格,数字被填充颜色并与背景区分开 |
代码示例 倒计时
在界面上创建⼀个 QLCDNumber , 初始值设为 10.
修改 widget.h
代码, 创建⼀个 QTimer 成员, 和⼀个 updateTime 函数
QTimer* timer;
void updateTime();
修改 widget.cpp, 在构造函数中初始化 QTimer
QTimer
表示定时器. 通过 start 方法启动定时器之后, 就会每隔⼀定周期, 触发⼀次QTimer::timeout
信号- 使用
connect
把QTimer::timeout
信号和Widget::updateTime
连接起来, 意味着每次触发QTimer::timeout
都会执Widget::updateTime
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建 QTimer 实例
timer = new QTimer(this);
// 连接信号槽. QTimer 会每隔⼀定的时间触发⼀个 timeout 信号. 现在把 timeout 信号
和 updateTime 连接起来.
// 此时意味着每次触发 timeout 信号都会伴随 updateTime 函数的执⾏.
connect(timer, &QTimer::timeout, this, &Widget::updateTime);
// 启动 QTimer, 并且规定每隔 1000ms 触发⼀次 timeout 信号.
timer->start(1000);
}
修改 widget.cpp, 实现 updateTime
- 通过 intValue 获取到 QLCDNumber 内部的数值
- 如果 value 的值归 0 了, 就停止 QTimer . 接下来 QTimer 也就不会触发 timeout 信号了.
#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(10);//设置初始值
//创建QTimer示例
timer= new QTimer(this);
//timer的信号与槽函数链接
connect(timer,&QTimer::timeout,this,&Widget::handle);
//启动定时器 参数出发的是timeout的周期, 单位是ms
timer->start(1000);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handle()
{
//拿到lcdnumber数值
int val = ui->lcdNumber->intValue();
if(val<0)
{
timer->stop();
return;
}
ui->lcdNumber->display(val-1);
}
执行程序, 可以看到每隔⼀秒钟, 显示的数字就减少1.
针对上述代码, 存在两个问题:
- 上述代码如果直接在 Widget 构造函数中, 通过⼀个循环 + sleep 的⽅式是否可以呢?
代码形如
#include "widget.h"
#include "ui_widget.h"
#include<windows.h>
#include<thread>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// int val = ui->lcdNumber->intValue();
// while (true) {
// std::this_thread::sleep_for(std::chrono::seconds(1));//休眠一秒
// if(val<=0)
// {
// break;
// }
// val--;
// ui->lcdNumber->display(--val);
// }
std::thread t([this](){
int val = this->ui->lcdNumber->intValue();
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
if(val<=0)
{
break;
}
val--;
ui->lcdNumber->display(val);//修改界面
}
});
}
Widget::~Widget()
{
delete ui;
}
这里运行出来是会报错的
这个代码同样是不行的. Qt 中规定, 任何对于 GUI 上内容的操作, 必须在 主线程 中完成. 像 Widget 构造
函数, 以及 connect 连接的 slot 函数, 都是在主线程中调用的. 而我们自己创建的线程则不是
当我们自己的线程中尝试对界面元素进行修改时, Qt 程序往往会直接崩溃.
2.3 ProgressBar
使⽤ QProgressBar
表示一个进度条.
核心属性
属性 | 说明 |
---|---|
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 :表示总时间(以毫秒为单位) |
代码示例 设置进度条按时间增长
在界面上创建进度条, objectName 为 progressBar
其中最小值设为 0, 最大值设为 100. 当前值设为 0.
QTimer* timer;
void updateProgressBar ();
修改 widget.cpp, 初始化 QTimer
- 此处设置 100ms 触发⼀次 timeout 信号. 也就是⼀秒钟触发 10 次.
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
timer = new QTimer(this);//创建一个timer对象
connect(timer,&QTimer::timeout,this,&Widget::handle);
timer->start(100);//启动进度条
}
Widget::~Widget()
{
delete ui;
}
void Widget::handle()
{
//获取进度条当前的数值
int val = ui->progressBar->value();
if(val>100)
{
timer->stop();
return;
}
ui->progressBar->setValue(val +1);
}
运行程序, 可以看到进度条中的进度在快速增长
代码示例 创建⼀个红色的进度条
QProgressBar 同样也是 QWidget 的子类, 因此我们可以使用 styleSheet 通过样式来修改进度条的颜色
在界面上创建⼀个进度条.
在 Qt Designer 右侧的属性编辑器中, 找到 QWidget 的 styleSheet 属性。
编辑如下内容:
- 其中的 chunk 是选中进度条中的每个 “块” . 使用 QProgressBar::text 则可以选中文本.
QProgressBar::chunk {background-color: #FF0000;}
同时把 QProcessBar 的 alignment 属性设置为垂直水平居中.
此处如果不设置 alignment , 进度条中的数字会跑到左上角. 这个怀疑是 Qt 本身的 bug, 暂时只能先使用alignment 来手动调整下
执行程序, 可以看到如下效果. 我们就得到了⼀个红色的进度条
2.3 Calendar Widget
QCalendarWidget
表示⼀个 “日历” , 形如
核心属性
属性 | 说明 |
---|---|
selectDate | 当前选中的日期 |
minimumDate | 最小日期 |
maximumDate | 最大日期 |
firstDayOfWeek | 每周的第⼀天(也就是⽇历的第⼀列) 是周几. |
gridVisible | 是否显示表格的边框 |
selectionMode | 是否允许选择日期 |
navigationBarVisible | 日历上方标题是否显示 |
horizontalHeaderFormat | 日历上方标题显示的日期格式 |
verticalHeaderFormat | 日历第⼀列显示的内容格式 |
dateEditEnabled | 是否允许日期被编辑 |
重要信号
信号 | 说明 |
---|---|
selectionChanged(const QDate&) | 当选中的日期发生改变时发出 |
activated(const QDate&) | 当双击⼀个有效的日期或者按下回车键时发出,形参是⼀个QDate类型,保存了选中的日期 |
currentPageChanged(int,int) | 当年份月份改变时发出,形参表示改变后的新年份和月份 |
代码示例: 获取选中的日期
在界面上创建⼀个 QCalendarWidget
和 ⼀个 label
objectName
为 calendarWidget , label
给 QCalendarWidget
添加 slot
函数
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QDate>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_calendarWidget_selectionChanged()
{
QDate dat = ui->calendarWidget->selectedDate();
qDebug()<<dat;
ui->label->setText(dat.toString());//将日期设置到label标签中
}
执行程序, 可以看到当选择不同的日期时, label 中的内容就会随之改变.
三.输入类控件
3.1 Line Edit
QLineEdit 用来表示单行输入框. 可以输入⼀段文本, 但是不能换行
属性 | 说明 |
---|---|
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) | 当QLineEdit中的⽂本改变时,发出此信号,text是新的⽂本。代码对文本的修改能够触发这个信号. |
void textEdited(const QString &text)) | 当QLineEdit中的⽂本改变时,发出此信号,text是新的⽂本。代码对⽂本的修改不能触发这个信号 |
代码示例: 录入个人信息
在界面上创建三个输⼊框和两个单选按钮, ⼀个普通按钮.
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->lineEdit_name->setPlaceholderText("请输入姓名");
ui->lineEdit_name->setClearButtonEnabled(true);//输入框旁边会出现 x号
ui->lineEdit_pass->setPlaceholderText("请输入密码");
ui->lineEdit_pass->setClearButtonEnabled(true);
ui->lineEdit_pass->setEchoMode(QLineEdit::Password);//密码的样式
ui->lineEdit_phone->setPlaceholderText("请输入电话号码");
ui->lineEdit_phone->setClearButtonEnabled(true);
ui->lineEdit_phone->setInputMask("000-0000-0000");//固定格式
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
QString gender = ui->radioButton_man->isChecked()?"男":"女";
qDebug() << "姓名: " << ui->lineEdit_name->text()
<< "密码: " << ui->lineEdit_pass->text()
<< "性别: " << gender
<< "电话: " << ui->lineEdit_phone->text();
}
执行程序, 可以看到, 随着用户输⼊内容之后, 点击按钮, 就能打印到输⼊的信息
代码示例: 使用正则表达式验证输入框的数据
此处要求在输入框中输⼊⼀个合法的电话号码(1 开头, 11 位, 全都是数字). 如果验证不通过, 则确定按钮无法点击.
关于正则表达式
正则表达式是⼀种在计算机中常用的, 使用特殊字符描述⼀个字符串的特征的机制. 在进行字符串匹配时非常有用.
正则表达式文档
在界面上创建输⼊框和⼀个按钮.
编写 widget.cpp, 把按钮初始 enabled 设为 false. 给输⼊框添加验证器.
- 使用 QRegExp 创建⼀个正则表达式对象. “^1\d{10}$” 表示 “以 1 开头, 后面跟上任意的10个十进制数字”.
- 使用 QRegExpValidator 创建⼀个验证器对象. Qt 中内置了四个主要的验证器对象
编写 widget.cpp, 给 lineEdit 添加 textEdited 信号的 slot 函数
#include "widget.h"
#include "ui_widget.h"
#include<QRegExpValidator>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//给单行输入框设置验证器,基于正则表达式完成
QRegExp reg("^1\\d{10}$");//简单的验证手机号码的正则表达式 ^1\\d{10}$
// ^ 表示以什么开头
//^ 后面的1,意识就是以1开头
// \d 表示数字,为了在C++字符串中使用与要写 \\d
// {10} 表示前面的内容重复出现10次 \d 数字要重复出现10次
//$ 表示结尾
ui->lineEdit->setValidator(new QRegExpValidator(reg));//设置验证器
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_lineEdit_textEdited(const QString &text)
{
QString content = text;
int pos = 0;
if(ui->lineEdit->validator()->validate(content,pos)==QValidator::Acceptable)
{
//验证通过
ui->pushButton->setEnabled(true);
}
else {
//验证不通过
ui->pushButton->setEnabled(false);
}
}
代码示例: 验证两次输入的密码⼀致
在界面上创建两个输⼊框和⼀个 label
代码
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//初始化,把输入框的echoMode设置一下
ui->lineEdit->setEchoMode(QLineEdit::Password);
ui->lineEdit_2->setEchoMode(QLineEdit::Password);
ui->label->setText("密码为空");
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_lineEdit_textEdited(const QString &arg1)
{
(void)arg1;
this->compare();
}
void Widget::on_lineEdit_2_textEdited(const QString &arg1)
{
(void)arg1;
this->compare();
}
void Widget::compare()
{
const QString& s1 = ui->lineEdit->text();
const QString& s2 = ui->lineEdit_2->text();
if(s1.isEmpty()&&s2.isEmpty())
{
ui->label->setText("密码为空");
}
else if(s1==s2)
{
ui->label->setText("两次输入的密码一样");
}
else {
ui->label->setText("输入的密码不一样");
}
}
执行程序, 观察效果.
可以看到当两个输⼊框内的密码相同时, 就会提示密码相同.
代码示例: 切换显示密码
创建⼀个输⼊框和⼀个复选按钮
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//初始情况下,输入框按照密码方式来显示
ui->lineEdit->setEchoMode(QLineEdit::Password);
ui->lineEdit->setClearButtonEnabled(true);
ui->lineEdit->setPlaceholderText("请输入密码");//输入框提示
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_checkBox_toggled(bool checked)
{
if(checked)
{
//true则是“显示密码”状态,把输入框地显示模式,设为Normal
ui->lineEdit->setEchoMode(QLineEdit::Normal);
}
else {
//false 则是“隐藏密码”状态,把输入框地显示模式,设为password
ui->lineEdit->setEchoMode(QLineEdit::Password);
}
}
执行程序, 可以看到切换复选框的状态, 就可以控制输⼊框显示密码
3.2 TextEdit
QTextEdit
表示多行输入框. 也是⼀个富⽂本 & markdown 编辑器.
并且能在内容超出编辑框范围时⾃动提供滚动条.
核心属性
属性 | 说明 |
---|---|
markdown | 输⼊框内持有的内容. ⽀持 markdown 格式. 能够⾃动的对markdown ⽂本进⾏渲染成 html |
html | 输⼊框内持有的内容. 可以⽀持⼤部分 html 标签. 包括 img 和 table 等. |
placeHolderText | 输⼊框为空时提⽰的内容. |
readOnly | 是否是只读的 |
undoRedoEnable 是否开启 undo / redo 功能. | 按下 ctrl + z 触发 undo按下 ctrl + y 触发 redo |
autoFormating | 开启⾃动格式化. |
tabstopWidth | 按下缩进占多少空间 |
overwriteMode | 是否开启覆盖写模式 |
acceptRichText | 是否接收富⽂本内容 |
verticalScrollBarPolicy | 垂直⽅向滚动条的出现策略 |
horizontalScrollBarPolicy | ⽔平⽅向滚动条的出现策略 Qt::ScrollBarAsNeeded : 根据内容⾃动决定是否需要滚动条。这是默认值。 Qt::ScrollBarAlwaysOff : 总是关闭滚动条。Qt::ScrollBarAlwaysOn : 总是显⽰滚动条。 |
核心信号
信号 | 说明 |
---|---|
textChanged() | ⽂本内容改变时触发 |
selectionChanged() | 选中范围改变时触发 |
cursorPositionChanged() | 光标移动时触发 |
undoAvailable(bool) | 可以进⾏ undo 操作时触发 |
redoAvailable(bool) | 可以进⾏ redo 操作时触发 |
copyAvaiable(bool) | ⽂本被选中/取消选中时触发 |
代码示例: 获取多行输⼊框的内容
创建⼀个多行输⼊框和⼀个label
给多行输⼊框添加 slot 函数. 处理 textChanged 信号
- 通过 toPlainText 方法获取到内部的文本
- 类似的, QTextEdit 还提供了 toMarkdown 和 toHtml . 根据需要我们调整不同的获取方式.
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_textEdit_textChanged()
{
//获取到多行输入框中地内容
const QString& content = ui->textEdit->toPlainText();
qDebug() << content;
ui->label->setText(content);
}
执行程序, 可以看到当输⼊框中的内容发⽣变化时, label 中的内容同步发生改变.
代码示例: 验证输⼊框的各种信号
创建多行输⼊框
给输⼊框添加以下几个 slot 函数
- QTextEdit 中包含了⼀个 QTextCursor 对象, 通过这个对象可以获取到当前光标位置和选中的内容.
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
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();//toPlainText()获取内部文本
}
void Widget::on_textEdit_selectionChanged()
{
const QTextCursor& cursor = ui->textEdit->textCursor();
qDebug() << "[selectionChanged] " << cursor.selectedText();
}
void Widget::on_textEdit_cursorPositionChanged()
{
//光标位置改变就出发信号
const QTextCursor& cursor = ui->textEdit->textCursor();
qDebug() << "[cursorPositionChanged] " << cursor.position();
}
void Widget::on_textEdit_undoAvailable(bool b)
{
qDebug() << "[undoAvailable] " << b;
}
void Widget::on_textEdit_redoAvailable(bool b)
{
qDebug() << "[redoAvailable] " << b;
}
void Widget::on_textEdit_copyAvailable(bool b)
{
qDebug() << "[copyAvailable] " << b;
}
执行程序, 观察结果.
可以看到:
-
编写内容时, textChanged 和 cursorPositionChanged 会触发
-
选中⼀段⽂本时会触发.
-
按下ctrl+z时会触发
-
按下ctrl+y时会触发
3.3 Combo Box
QComboBox .
表示下拉框
核心属性
属性 | 说明 |
---|---|
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) | 当编辑框中的⽂本改变时发出editable 为 true 时有效 |
代码示例: 使用下拉框模拟⻨当劳点餐
在界面上创建三个下拉框, 和⼀个按钮
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//
ui->comboBox->addItem("巨无霸");
ui->comboBox->addItem("⻨辣鸡腿堡");
ui->comboBox_2->addItem("薯条");
ui->comboBox_2->addItem("⻨辣鸡翅");
ui->comboBox_3->addItem("可乐");
ui->comboBox_3->addItem("雪碧");
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
qDebug() << "汉堡选择: " << ui->comboBox->currentText();
qDebug() << "⼩⻝选择: " << ui->comboBox_2->currentText();
qDebug() << "饮料选择: " << ui->comboBox_3->currentText();
}
执行程序, 可以看到, 在点击确定按钮时, 就能获取到当前下拉框中选中的内容.
代码示例: 从文件中加载下拉框的选项
很多时候下拉框的选项并非是固定的, 而是通过读取文件/读取网络获取到的.
在界面上创建⼀个下拉框
创建⽂件 d:/config.txt , 编写选项. 每个选项占⼀行.
形如:
修改 widget.cpp, 从⽂件中读取选项.
- 使用ifstream 打开⽂件
- 使⽤ getline 读取每⼀行
- 使⽤ QString::fromStdString 把 std::string 转成 QString
#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("C:/Users/zyy/Desktop/config.txt");//打开文件的操作
if(!file.is_open())
{
qDebug()<<"文件打开失败";
return;
}
//按行读取文本内容
//grtline
std::string line;
while (std::getline(file,line)) {
//取到每一行的内容,设置到下拉框中
ui->comboBox->addItem(QString::fromStdString(line));
//QString::fromStdString把stdstring转换为Qstring
//把Qstring转换为stdstring
// QString s;
// s.toStdString();
}
file.close();
}
Widget::~Widget()
{
delete ui;
}
执行程序, 可以看到⽂件内容已经被加载到下拉框中.
注意
:Qt 中也提供了 QFile 实现读写⽂件的功能. 当然使⽤ C++ 标准库的 std::fstream 也是完全可以的.
3.4 spin Box
使⽤ QSpinBox
或者 QDoubleSpinBox
表示 “微调框”, 它是带有按钮的输入框. 可以用来输⼊整
数/浮点数. 通过点击按钮来修改数值大小.
QSpinBox 关键属性
属性 | 说明 |
---|---|
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 带有 前缀 和 后缀. |
valueChanged(int) | 微调框的⽂本发⽣改变时会触发.参数 int, 表示当前的数值. |
代码示例: 调整⻨当劳购物车中的份数
在界面上创建下列内容
- 三个下拉框: objectName 为 comboBox 到 comboBox_3
- 三个微调框: objectName 为 spinBox 到 spinBox_3
- ⼀个按钮: objectName 为 pushButton
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 初始化下拉框
ui->comboBox->addItem("巨⽆霸");
ui->comboBox->addItem("⻨辣鸡腿堡");
ui->comboBox_2->addItem("薯条");
ui->comboBox_2->addItem("⻨辣鸡翅");
ui->comboBox_3->addItem("可乐");
ui->comboBox_3->addItem("雪碧");
// 初始化微调框
ui->spinBox->setValue(1);
ui->spinBox->setRange(1, 5);
ui->spinBox_2->setValue(1);
ui->spinBox_2->setRange(1, 5);
ui->spinBox_3->setValue(1);
ui->spinBox_3->setRange(1, 5);
}
void Widget::on_pushButton_clicked()
{
qDebug() << "当前下单的内容: "
<< ui->comboBox->currentText() << ": " << ui->spinBox->value()
<< ui->comboBox_2->currentText() << ": " << ui->spinBox_2->value()
<< ui->comboBox_3->currentText() << ": " << ui->spinBox_3-
>value();
}
执行程序, 可以看到当用户选择不同的内容时, 点击按钮就能获取到对应的结果. 同时我们也无法输⼊⼀些超出范围的非法值
3.5 Date Edit & Time Edit
使⽤ QDateEdit 作为日期的微调框.
QDateTimeEdit 核心属性
属性 | 说明 |
---|---|
dateTime | 时间⽇期的值. 形如 2000/1/1 0:00:00 |
date | 单纯⽇期的值. 形如 2001/1/1 |
time | 单纯时间的值. 形如 0:00:00 |
displayFormat | 时间⽇期格式. 形如 yyyy/M/d H:mm y 表⽰年份 M 表⽰⽉份 d 表⽰⽇期 H 表⽰⼩时 m 表⽰分钟 s 表⽰秒 注意: 这⾥的格式化符号的含义, 不要记忆. 不同语⾔/库的设定规则是存在差异的. ⼀定是⽤的时候再去查. |
minimumDateTime | 最⼩时间⽇期 |
maximumDateTime | 最⼤时间⽇期 |
timeSpec | Qt::LocalTime :显⽰本地时间。 Qt::UTC :显示协调世界时(UTC) Qt::OffsetFromUTC :显⽰相对于UTC的偏移量(时差) |
核心信号
信号 | 说明 |
---|---|
dateChanged(QDate) | ⽇期改变时触发. |
timeChanged(QTime) | 时间改变时触发. |
dateTimeChanged(QDateTime) | 时间⽇期任意⼀个改变时触发. |
代码示例: 实现日期计算器
在界面上创建两个 QDateTimeEdit
和⼀个按钮, ⼀个 label QDateTimeEdit
的 objectName 为 dateTimeEdit_old 和 dateTimeEdit_new
编写计算按钮的 slot 函数
- 使用 daysTo 函数可以计算两个日期的天数.
- 使用 secsTo 函数可以计算两个时间的秒数.
- 通过 (秒数 / 3600) 换算成小时数, 再余上 24 得到零几个小时.
- 使⽤ QString::number 把整数转成 QString 进行拼接.
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
//先获取两个输入框的时间
QDateTime timeOld = ui->dateTimeEdit->dateTime();
QDateTime timeNew = ui->dateTimeEdit_2->dateTime();
qDebug()<<timeOld<<timeNew;
//计算日期的差值
int days = timeOld.daysTo(timeNew);//天数的差别
int seconds = timeOld.secsTo(timeNew);//秒数的差别
//要把秒数换算成小时
int hous = (seconds/3600)%24;
int day = (seconds/3600)/24;
//把计算结果放到label中
ui->label->setText(QString("爱你已经持续了 ") +
QString::number(days) +
QString("天零")+QString::number(hous) +
QString("小时"));
}
代码结果
3.6 Dial
使⽤ QDial 表示⼀个 旋钮
有些程序, 通过⿏标拖动旋钮旋转, 即可完成⼀些相关的设置
核心属性
属性 | 说明 |
---|---|
value | 持有的数值. |
minimum | 最⼩值 |
maximum | 最⼤值 |
singleStep | 按下⽅向键的时候改变的步⻓. |
pageStep | 按下 pageUp / pageDown 的时候改变的步⻓. |
sliderPosition | 界⾯上旋钮显⽰的 初始位置 |
tracking | 外观是否会跟踪数值变化.默认值为 true. ⼀般不需要修改. |
wrapping | 是否允许循环调整.即数值如果超过最⼤值, 是否允许回到最⼩值.(调整过程能否 “套圈”) |
notchesVisible | 是否显⽰ 刻度线 |
notchTarget | 刻度线之间的相对位置.数字越⼤, 刻度线越稀疏. |
核心信号
属性 | 说明 |
---|---|
valueChanged(int) | 数值改变时触发 |
rangeChanged(int, int) | 范围变化时触发 |
代码示例: 调整窗口透明度
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_dial_valueChanged(int value)
{
qDebug()<<value;
this->setWindowOpacity((double)value/100);
}
运行程序, 观察效果. 可以看到随着拖动旋钮旋转, 不透明度发生明显变化
3.6 Slider
使用 QSlider 表示⼀个滑动条.
QSlider 和 QDial 都是继承⾃ QAbstractSlider , 因此⽤法上基本相同.
核心属性
属性 | 说明 |
---|---|
value | 持有的数值. |
minimum | 最⼩值 |
maximum | 最⼤值 |
singleStep | 按下⽅向键的时候改变的步⻓. |
pageStep | 按下 pageUp / pageDown 的时候改变的步⻓. |
sliderPosition | 滑动条显⽰的 初始位置 |
tracking | 外观是否会跟踪数值变化.默认值为 true. ⼀般不需要修改. |
orientation 滑动条的⽅向是⽔平还是垂直 | |
invertedAppearance | 是否要翻转滑动条的⽅向 |
tickPosition | 刻度的位置. |
tickInterval | 刻度的密集程度 |
核心信号
属性 | 说明 |
---|---|
valueChanged(int) | 数值改变时触发 |
rangeChanged(int, int) | 范围变化时触发 |
代码⽰例: 调整窗⼝大小
在界⾯上创建两个滑动条, 分别是⽔平和垂直滑动条.
代码
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->horizontalSlider->setMinimum(100);
ui->horizontalSlider->setMaximum(2000);
ui->horizontalSlider->setValue(800);
ui->horizontalSlider->setSingleStep(500);//按下⽅向键的时候改变的步⻓.
ui->verticalSlider->setMinimum(100);
ui->verticalSlider->setMaximum(1500);
ui->verticalSlider->setValue(600);
ui->verticalSlider->setSingleStep(50);
// 翻转朝向, 默认滑块从下向上增⻓, 改成从上往下增⻓.
ui->verticalSlider->setInvertedAppearance(true);
}
Widget::~Widget()
{
delete ui;
ui->setupUi(this);
}
void Widget::on_horizontalSlider_valueChanged(int value)
{
const QRect rect = this->geometry();
this->setGeometry(rect.x(), rect.y(), value, rect.height());
qDebug() << value;
}
void Widget::on_verticalSlider_valueChanged(int value)
{
const QRect rect = this->geometry();
this->setGeometry(rect.x(), rect.y(), rect.width(), value);
qDebug() << value;
}
执行程序, 可以看到调整滑动条, 窗⼝小就会随之改变
代码示例: 通过⾃定义快捷键调整滑动条位置
设置 - 减小 value, 设置 = 增加 value.
- 默认情况下滑动条可以通过 方向键 或者 pageUp / pageDown 调整大小.
在界⾯上创建滑动条和 label
代码
#include "widget.h"
#include "ui_widget.h"
#include<QShortcut>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//使用快捷键 QShirtCut
QShortcut* shortCut1 = new QShortcut(this);
shortCut1->setKey(QKeySequence("-"));
QShortcut* shortCut2 = new QShortcut(this);
shortCut2->setKey(QKeySequence("="));
//使用信号槽,感知快捷键被按下
connect(shortCut1,&QShortcut::activated,this,&Widget::subValue);
connect(shortCut2,&QShortcut::activated,this,&Widget::addValue);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_horizontalSlider_valueChanged(int value)
{
ui->label->setText("当前值为:"+QString::number(value));
}
void Widget::subValue()
{
//获取到当前的值
int value = ui->horizontalSlider->value();
if(value <= ui->horizontalSlider->minimum())//如果小于最小值,直接return
{
return;
}
ui->horizontalSlider->setValue(value - 5);
}
void Widget::addValue()
{
int value = ui->horizontalSlider->value();
if(value>= ui->horizontalSlider->maximum())
{
return;
}
ui->horizontalSlider->setValue(value+5);
}
执行程序, 观察效果. 可以看到此时按下 - 和 = 就可以调整 value 的值了.
四.多元素控件
Qt 中提供的多元素控件有:
- QListWidget
- QListView
- QTableWidget
- QTableView
- QTreeWidget
- QTreeView
4.1 List Widget
使用QListWidget 能够显⽰⼀个纵向的列表. 形如
每个选项可以选中
核心属性
属性 | 说明 |
---|---|
currentRow | 当前被选中的是第几⾏ |
count | ⼀共有多少行 |
sortingEnabled | 是否允许排序 |
isWrapping | 是否允许换行 |
itemAlignment | 元素的对齐方式 |
selectRectVisible | 被选中的元素矩形是否可见 |
spacing | 元素之间的间隔 |
核心方法
方法 | 说明 |
---|---|
addItem(const QString& label) | |
addItem(QListWidgetItem *item) | 列表中添加元素. |
currentItem() | 返回 QListWidgetItem* 表⽰当前选中的元素 |
setCurrentItem(QListWidgetItem* item) | 设置选中哪个元素 |
setCurrentRow(int row) | 设置选中第⼏⾏的元素 |
insertItem(const QString& label, int row) insertItem(QListWidgetItem *item, int row) | 在指定的位置插⼊元素 |
item(int row) | 返回 QListWidgetItem* 表⽰第 row ⾏的元素 |
takeItem(int row) | 删除指定⾏的元素, 返回 QListWidgetItem* 表⽰是哪个元素被删除了 |
核心信号
方法 | 说明 |
---|---|
currentItemChanged(QListWidgetItemcurrent, QListWidgetItem old) | 选中不同元素时会触发. 参数是当前选中的元素和之前选中的元素. |
currentRowChanged(int) | 选中不同元素时会触发. 参数是当前选中元素的⾏数. |
itemClicked(QListWidgetItem* item) | 点击某个元素时触发 |
itemDoubleClicked(QListWidgetItem*item) | 双击某个元素时触发 |
itemEntered(QListWidgetItem* item) | ⿏标进⼊元素时触发 |
在上述介绍中, 涉及到⼀个关键的类, QListWidgetItem .
这个类表⽰ QListWidget 中的⼀个元素.
核心方法如下, 本质上就是⼀个 “文本+图标” 构成的.
方法 | 说明 |
---|---|
setFont | 设置字体 |
setIcon | 设置图标 |
setHidden | 设置隐藏 |
setSizeHint | 设置尺⼨ |
setSelected | 设置是否选中 |
setText | 设置⽂本 |
setTextAlignment | 设 置⽂本对齐方式. |
代码示例: 使用 ListWidget
在界面上创建⼀个 ListView , 右键 => 变形为 => ListWidget , 再创建⼀个 lineEdit 和 两个按钮
#include "widget.h"
#include "ui_widget.h"
#include<qDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//往这里添加元素
ui->listWidget->addItem("c++");
ui->listWidget->addItem("java");
ui->listWidget->addItem("phony");
//在QListWidgetItem中,设置图标,文字大小等等
// ui->listWidget->addItem(new QListWidgetItem("c++"));
// ui->listWidget->addItem(new QListWidgetItem("java"));
// ui->listWidget->addItem(new QListWidgetItem("c++"));
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_insert_clicked()
{
//先获取到输入框中的内容
const QString&text = ui->lineEdit->text();
//添加到QListWidgetItem
ui->listWidget->addItem(text);
}
void Widget::on_pushButton_delete_clicked()
{
//先获取被选中的元素
int roe = ui->listWidget->currentRow();//返回被选中元素是第⼏⾏
if(roe<0)
{
return;
}
//按照行号删除
ui->listWidget->takeItem(roe);
}
void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
//通过这个槽函数感知到变化
if(current != nullptr)
{
qDebug()<<"当前选中的元素:"<<current->text();
}
if(previous != nullptr)
{
qDebug()<<"上次选中的元素:"<<previous->text();
}
}
执行程序, 观察效果. 可以新增元素, 选中元素, 删除元素.
4.2 Table Widget
使⽤ QTableWidget
表示⼀个表格控件. ⼀个表格中包含若干行, 每⼀行⼜包含若⼲列.表格中的每个单元格, 是⼀个QTableWidgetItem 对象.
QTableWidget
核心方法
方法 | 属性 |
---|---|
row() | 获取当前是第几行 |
column() | 获取当前是第几列 |
setText(const QString&) | 设置⽂本 |
setTextAlignment(int) | 设置⽂本对齐 |
setIcon(const QIcon&) | 设置图标 |
setSelected(bool) | 设置被选中 |
setSizeHints(const QSize&) | 设置尺⼨ |
setFont(const QFont&) | 设置字体 |
代码示例: 使用 QTableWidget
在界面上创建 QTableWidget 和 四个按钮, ⼀个输入框
代码
#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->insertColumn(2);
//设置列名
ui->tableWidget->setHorizontalHeaderItem(0,new QTableWidgetItem("姓名"));
ui->tableWidget->setHorizontalHeaderItem(1,new QTableWidgetItem("年龄"));
ui->tableWidget->setHorizontalHeaderItem(2,new QTableWidgetItem("学号"));
//添加数据
ui->tableWidget->setItem(0,0,new QTableWidgetItem("1001"));
ui->tableWidget->setItem(0,1,new QTableWidgetItem("张三"));
ui->tableWidget->setItem(0,2,new QTableWidgetItem("20"));
ui->tableWidget->setItem(1,0,new QTableWidgetItem("1002"));
ui->tableWidget->setItem(1,1,new QTableWidgetItem("李四"));
ui->tableWidget->setItem(1,2,new QTableWidgetItem("30"));
ui->tableWidget->setItem(2,0,new QTableWidgetItem("1003"));
ui->tableWidget->setItem(2,1,new QTableWidgetItem("王五"));
ui->tableWidget->setItem(2,2,new QTableWidgetItem("40"));
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_row_clicked()
{
//获取当前行数
int row = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(row);
qDebug()<<row;
ui->pushButton_row->setShortcut(QKeySequence("="));
}
void Widget::on_pushButton_col_clicked()
{
//获取列
int col =ui->tableWidget->columnCount();
ui->tableWidget->insertColumn(col);
//设置列名
const QString&text = ui->lineEdit->text();
ui->tableWidget->setHorizontalHeaderItem(col,new QTableWidgetItem(text));
}
void Widget::on_pushButton_delrow_clicked()
{
//删除行
int row =ui->tableWidget->rowCount();
ui->tableWidget->removeRow(row);
}
void Widget::on_pushButton_delcol_clicked()
{
int col =ui->tableWidget->columnCount();
ui->tableWidget->removeColumn(col);
}
执行程序, 即可完成表格的基本操作
4.3 Tree Widget
使用 QTreeWidget 表示⼀个树形控件. 里面的每个元素, 都是⼀个 QTreeWidgetItem , 每个QTreeWidgetItem 可以包含多个⽂本和图标, 每个文本/图标为⼀个 列
可以给 QTreeWidget 设置顶层节点(顶层节点可以有多个), 然后再给顶层节点添加子节点, 从而构成树形结构
QTreeWidget 核心方法
方法 | 说明 |
---|---|
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 名称. |
QTreeWidget 核心信号
信号 | 说明 |
---|---|
currentItemChanged(QTreeWidgetItemcurrent, QTreeWidgetItem old) | 切换选中元素时触发 |
itemClicked(QTreeWidgetItem* item, int col) | 点击元素时触发 |
itemDoubleClicked(QTreeWidgetItem* item,int col) | 双击元素时触发 |
itemEntered(QTreeWidgetItem* item, int col) | ⿏标进⼊时触发 |
itemExpanded(QTreeWidgetItem* item) | 元素被展开时触发 |
itemCollapsend(QTreeWidgetItem* item) | 元素被折叠时触发 |
QTreeWidgetItem 核心属性
属性 | 说明 |
---|---|
text | 持有的⽂本 |
textAlignment | ⽂本对⻬⽅式 |
icon | 持有的图表 |
font | ⽂本字体 |
hidden | 是否隐藏 |
disabled | 是否禁⽤ |
expand | 是否展开 |
sizeHint | 尺⼨⼤⼩ |
selected | 是否选中 |
QTreeWidgetItem 核心方法
方法 | 说明 |
---|---|
addChild(QTreeWidgetItem* child) | 新增⼦节点 |
childCount() | ⼦节点的个数 |
child(int index) | 获取指定下标的⼦节点. 返回 QTreeWidgetItem* |
takeChild(int index) | 删除对应下标的⼦节点 |
removeChild(QTreeWidgetItem*child) | 删除对应的⼦节点 |
parent() | 获取该元素的⽗节点 |
代码示例: 使用 QTreeWidget
在界面上创建⼀个 TreeView , 右键 => 变形为 => TreeWidget , 再创建⼀个 lineEdit 和 两个按钮.
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置根节点的名字
ui->treeWidget->setHeaderLabel("动物");
//新增底层节点
QTreeWidgetItem* item1 = new QTreeWidgetItem();
item1->setText(0,"猫");//每个节点可以设置多列
//添加到顶层节点中
ui->treeWidget->addTopLevelItem(item1);
QTreeWidgetItem* item2 = new QTreeWidgetItem();
item2->setText(0,"狗");//每个节点可以设置多列
//添加到顶层节点中
ui->treeWidget->addTopLevelItem(item2);
QTreeWidgetItem* item3 = new QTreeWidgetItem();
item3->setText(0,"鸟");//每个节点可以设置多列
//添加到顶层节点中
ui->treeWidget->addTopLevelItem(item3);
//添加节点
QTreeWidgetItem * item4 = new QTreeWidgetItem();
item4->setText(0,"中华田园猫");
item1->addChild(item4);//添加子节点
QTreeWidgetItem * item5 = new QTreeWidgetItem();
item5->setText(0,"布偶猫");
item1->addChild(item4);
QTreeWidgetItem * item6 = new QTreeWidgetItem();
item6->setText(0,"暹罗");
item1->addChild(item6);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_inserttop_clicked()
{
//先获取到输入框里的内容
const QString&text= ui->lineEdit->text();
QTreeWidgetItem*item= new QTreeWidgetItem();
item->setText(0,text);
//添加到顶层节点中
ui->treeWidget->addTopLevelItem(item);
}
void Widget::on_pushButton_insertitem_clicked()
{
//获取到当前选中的节点
QTreeWidgetItem * currentItem= ui->treeWidget->currentItem();//获取到当前选中的节点, 返回 QTreeWidgetItem*
if(currentItem == nullptr)
{
return ;
}
//先获取到输入框里的内容
const QString&text= ui->lineEdit->text();
//构造一个QTreeWidgetItem
QTreeWidgetItem*item= new QTreeWidgetItem();
item->setText(0,text);
//插入到选中节点的子节点
currentItem->addChild(item);
}
void Widget::on_pushButton_delete_clicked()
{
//先获取到选中的元素
QTreeWidgetItem* currentItem= ui->treeWidget->currentItem();
if(currentItem==nullptr)//判空
{
return ;
}
//删除选中的元素,需要先获取到父元素,通过父元素进行删除
QTreeWidgetItem* parent = currentItem->parent();
if(parent==nullptr)
{
//顶层元素
int index = ui->treeWidget->indexOfTopLevelItem(currentItem);//获取前节点第几个
ui->treeWidget->takeTopLevelItem(index);
}else{
//普通元素
parent->removeChild(currentItem);
}
}
五.容器类控件
5.1Group Box
使用 QGroupBox 实现⼀个带有标题的分组框. 可以把其他的控件放到里面作为⼀组. 这样看起来能更好看⼀点.
核心属性
属性 | 说明 |
---|---|
title | 分组框的标题 |
alignment | 分组框内部内容的对⻬⽅式 |
flat | 是否是 “扁平” 模式 |
checkable | 是否可选择.设为 true, 则在 title 前⽅会多出⼀个可勾选的部分. |
checked | 描述分组框的选择状态 (前提是 checkable 为 true) |
代码⽰例: 给麦当劳案例加上分组框
在界面上创建三个分组框, 并且在分组框内部创建下拉框和微调框
代码
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->comboBox->addItem("巨⽆霸");
ui->comboBox->addItem("⻨辣鸡腿堡");
ui->comboBox_2->addItem("薯条");
ui->comboBox_2->addItem("⻨辣鸡翅");
ui->comboBox_3->addItem("可乐");
ui->comboBox_3->addItem("雪碧");
}
运行程序, 观察效果
5.2Tab Widget
使用 QTabWidget
实现⼀个带有标签页的控件, 可以往里面添加⼀些 widget. 进⼀步的就可以通过标签页来切换.
核心属性
属性 | 说明 |
---|---|
tabPosition 标签⻚所在的位置. | |
• North 上⽅ | |
• South 下⽅ | |
• West 左侧 | |
• East 右侧 | |
currentIndex 当前选中了第⼏个标签⻚ (从 0 开始计算) | |
currentTabText 当前选中的标签⻚的⽂本 | |
currentTabName 当前选中的标签⻚的名字 | |
currentTabIcon 当前选中的标签⻚的图标 | |
currentTabToolTip 当前选中的标签⻚的提⽰信息 | |
tabsCloseable 标签⻚是否可以关闭 | |
movable 标签⻚是否可以移动 |
核心信号
属性 | 说明 |
---|---|
currentChanged(int) 在标签⻚发⽣切换时触发, 参数为被点击的选项卡编号. | |
tabBarClicked(int) 在点击选项卡的标签条的时候触发. 参数为被点击的选项卡编号. | |
tabBarDoubleClicked(int) 在双击选项卡的标签条的时候触发. 参数为被点击的选项卡编号. | |
tabCloseRequest(int) 在标签⻚关闭时触发. 参数为被关闭的选项卡编号 |
代码示例: 使用标签页管理多组控件
在界面上创建⼀个 QTabWidget , 和两个按钮.
注意
:
QTabWidget
中的每个标签页都是⼀个QWidget
- 点击标签页, 就可以直接切换.
- 右键
QTabWidget
, 可以添加标签⻚或者删除标签页
#include "widget.h"
#include "ui_widget.h"
#include<QLabel>
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 现在每个标签按页中添加label
QLabel *label1 = new QLabel(ui->tab);//通过ui——>来访问
label1->setText("标签页1");
label1->resize(100,50);
QLabel *label2 = new QLabel(ui->tab_2);
label2->setText("标签页2");
label2->resize(100,50);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
//新增标签页,使用addtable
//参数1要指定 QWidget
//参数2指定这个标签页的text(标题)
int count = ui->tabWidget->count();//获取到数量
QWidget*z = new QWidget();
ui->tabWidget->addTab(z,QString("Tab ")+QString::number(count+1));
//添加Qlabel显示内容
QLabel* label = new QLabel(z);
label->setText(QString("标签页")+QString::number(count+1));
label->resize(100,50);
//自动选中新标签页
ui->tabWidget->setCurrentIndex(count);
}
void Widget::on_pushButton_2_clicked()
{
//获取到当前选中的标签页的下标
int index = ui->tabWidget->currentIndex();//下标
ui->tabWidget->removeTab(index);//删除标签
}
void Widget::on_tabWidget_currentChanged(int index)
{
qDebug()<<"当前选中的标签页"<<(index+1);
}
运行程序, 观察效果
- 点击新建标签页, 可以创建出新的标签.
- 点击删除当前标签页, 可以删除标签
- 切换标签页时, 可以看到 qDebug 打印出的标签页编号
六.布局管理器
6.1垂直布局
使用 QVBoxLayout
表⽰垂直的布局管理器. V 是 vertical 的缩写.
核心属性
属性 | 说明 |
---|---|
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上方边距 |
layoutBottomMargin | 下方边距 |
layoutSpacing | 相邻元素之间的间距 |
Layout 只是用于界面布局, 并没有提供信号
代码示例: 使用 QVBoxLayout 管理多个控件.
编写代码, 创建布局管理器和三个按钮. 并且把按钮添加到布局管理器中
- 使用 addWidget 把控件添加到布局管理器中
- 使用 setLayout 设置该布局管理器到 widget 中.
#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>
#include<QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建3个按钮,使用垂直布局管理
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;
}
运行程序, 可以看到此时界面上的按钮就存在于布局管理器中. 随着窗口尺寸变化而发生改变.
代码示例: 创建三个 QVBoxLayout
在界面上创建三个 QVBoxLayout , 每个 QVBoxLayout 各放三个按钮.
运行程序, 可以看到这些按钮已经自动排列好. 只不过当前这些按钮的位置不能随着窗口大小自动变化
6.2水平布局
使⽤ QHBoxLayout 表⽰垂直的布局管理器. H 是 horizontal 的缩写.
核心属性
属性 | 说明 |
---|---|
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上⽅边距 |
layoutBottomMargin | 下⽅边距 |
layoutSpacing | 相邻元素之间的间距 |
代码示例: 使用 QHBoxLayout 管理控件
编写代码, 创建布局管理器和三个按钮. 并且把按钮添加到布局管理器中.
#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>
#include<QHBoxLayout>
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");
QHBoxLayout*layout =new QHBoxLayout();
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
this->setLayout(layout);
}
Widget::~Widget()
{
delete ui;
}
运行程序, 可以看到此时界面上的按钮就存在于布局管理器中. 随着窗口尺寸变化而发生改变
代码示例: 嵌套的 layout
- 使用 addLayout 给 layout 中添加子 layout.
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建顶层 layout
QVBoxLayout* layoutParent = new QVBoxLayout();
this->setLayout(layoutParent);
// 添加两个按钮进去
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
layoutParent->addWidget(btn1);
layoutParent->addWidget(btn2);
// 创建⼦ layout
QHBoxLayout* layoutChild = new QHBoxLayout();
// 添加两个按钮进去
QPushButton* btn3 = new QPushButton("按钮3");
QPushButton* btn4 = new QPushButton("按钮4");
layoutChild->addWidget(btn3);
layoutChild->addWidget(btn4);
// 把这个⼦ layout 添加到 ⽗ layout 中
layoutParent->addLayout(layoutChild);
}
执⾏程序, 观察结果
6.3网格布局
Qt 中还提供了 QGridLayout
用来实现网格布局的效果. 可以达到 M * N 的这种网格的效果
核心属性
属性 | 说明 |
---|---|
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上⽅边距 |
layoutBottomMargin | 下⽅边距 |
layoutHorizontalSpacing | 相邻元素之间⽔平⽅向的间距 |
layoutVerticalSpacing | 相邻元素之间垂直⽅向的间距 |
layoutRowStretch | ⾏⽅向的拉伸系数 |
layoutColumnStretch | 列⽅向的拉伸系数 |
代码示例: 使用 QGridLayout 管理元素
代码中创建 QGridLayout 和 4 个按钮.
- 使用 addWidget 添加控件到布局管理器中. 但是添加的同时会指定两个坐标. 表示放在第几列, 第几列.
#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>
#include<QGridLayout>
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");
QPushButton * button4 = new QPushButton("按钮4");
QGridLayout*layout = new QGridLayout();
// layout->addWidget(button1,0,0);// 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);
this->setLayout(layout);
}
Widget::~Widget()
{
delete ui;
}
执行代码, 观察效果. 可以看到当前的这几个按钮是按照 2 行 2 列的方式排列的.
如果调整行列坐标为下列代码
// 创建⽹格布局管理器, 并且添加元素
QGridLayout* layout = new QGridLayout();
layout->addWidget(btn1, 0, 0);
layout->addWidget(btn2, 0, 1);
layout->addWidget(btn3, 0, 2);
layout->addWidget(btn4, 0, 3);
执行代码, 可以看到这几个按钮都在同⼀行了. 相当于 QHBoxLayout
如果调整行列坐标为下列代码
QGridLayout* layout = new QGridLayout();
layout->addWidget(btn1, 1, 0);
layout->addWidget(btn2, 2, 0);
layout->addWidget(btn3, 3, 0);
layout->addWidget(btn4, 4, 0);
执行代码, 可以看到这几个按钮都在同⼀列了. 相当于 QVBoxLayout
任意调整行列, 即可看到不同的效果.
// 创建⽹格布局管理器, 并且添加元素
QGridLayout* layout = new QGridLayout();
layout->addWidget(btn1, 0, 0);
layout->addWidget(btn2, 1, 1);
layout->addWidget(btn3, 2, 2);
layout->addWidget(btn4, 3, 3);
编写代码形如
QGridLayout* layout = new QGridLayout();
layout->addWidget(btn1, 0, 0);
layout->addWidget(btn2, 1, 0);
layout->addWidget(btn3, 2, 0);
layout->addWidget(btn4, 10, 0);
代码示例: 设置 QGridLayout 中元素的大小比例.
创建 6 个按钮, 按照 2 行 3 列的方式排列
- 使用 setColumnStretch 设置每⼀列的拉伸系数
#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>
#include<QGridLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建6个按钮 使用网格布局按照两行三列的方式布局
QPushButton* 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");
//创建网格布局管理器,把这些空间添加进去
QGridLayout* layout = new QGridLayout();
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);
this->setLayout(layout);
//设置水平拉伸系数 就是按照1:1:2的方式设置
// layout->setColumnStretch(0,1);
// layout->setColumnStretch(1,1);
// layout->setColumnStretch(2,2);
//第一列按钮固定
//拉伸系数为0就是不参与拉伸
layout->setColumnStretch(0,0);
layout->setColumnStretch(1,1);
layout->setColumnStretch(2,2);
}
Widget::~Widget()
{
delete ui;
}
执行程序, 可以看到每⼀列的宽度是不同的. 并且随着窗⼝调整动态变化.
代码示例: 设置垂直方向的拉伸系数
编写代码, 创建 6 个按钮, 按照 3 行 2 列方式排列.
使用 setSizePolicy 设置按钮的尺寸策略. 可选的值如下:
QSizePolicy::Ignored
: 忽略控件的尺⼨,不对布局产⽣影响QSizePolicy::Minimum
: 控件的最⼩尺⼨为固定值,布局时不会超过该值QSizePolicy::Maximum
: 控件的最⼤尺⼨为固定值,布局时不会⼩于该值。QSizePolicy::Preferred
: 控件的理想尺⼨为固定值,布局时会尽量接近该值。QSizePolicy::Expanding
: 控件的尺⼨可以根据空间调整,尽可能占据更多空间QSizePolicy::Shrinking
: 控件的尺⼨可以根据空间调整,尽可能缩⼩以适应空间。
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建 6 个按钮
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
QPushButton* btn3 = new QPushButton("按钮3");
QPushButton* btn4 = new QPushButton("按钮4");
QPushButton* btn5 = new QPushButton("按钮5");
QPushButton* btn6 = new QPushButton("按钮6");
// 设置按钮的 sizePolicy, 此时按钮的⽔平⽅向和垂直⽅向都会尽量舒展开
btn1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
btn2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
btn3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
btn4->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
btn5->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
btn6->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// 创建⽹格布局管理器, 并且添加元素
QGridLayout* layout = new QGridLayout();
layout->addWidget(btn1, 0, 0);
layout->addWidget(btn2, 0, 1);
layout->addWidget(btn3, 1, 0);
layout->addWidget(btn4, 1, 1);
layout->addWidget(btn5, 2, 0);
layout->addWidget(btn6, 2, 1);
// 设置拉伸⽐例
// 第 0 ⾏拉伸⽐例设为 1;
layout->setRowStretch(0, 1);
// 第 1 ⾏拉伸⽐例设为 0, 即为固定⼤⼩, 不参与拉伸
layout->setRowStretch(1, 0);
// 第 2 ⾏拉伸⽐例设为 3, 即为第 2 ⾏的宽度是第 0 ⾏的 3 倍
layout->setRowStretch(2, 3);
// 设置 layout 到窗⼝中.
this->setLayout(layout);
}
执行代码, 观察效果.
此时的按钮垂直方向都舒展开了. 并且调整窗口尺寸, 也会按照设定的比例同步变化.
6.4表单布局
除了上述的布局管理器之外, Qt 还提供了 QFormLayout , 属于是 QGridLayout 的特殊情况, 专门用于实现两列表单的布局.
代码示例: 使用 QFormLayout 创建表单.
编写代码, 创建 QFormLayout , 以及三个 label 和三个 lineEdit
- 使用 addRow 方法来添加⼀行. 每行包含两个控件. 第⼀个控件固定是 QLabel / ⽂本, 第⼆个控件则可以是任意控件.
- 如果把第⼀个参数填写为 NULL, 则什么都不显示
#include "widget.h"
#include "ui_widget.h"
#include<QFormLayout>
#include<QLabel>
#include<QLineEdit>
#include<QPushButton>
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置3行2列
QFormLayout* layout = new QFormLayout();
this->setLayout(layout);
//创建3个label作为第一列
QLabel*label1 = new QLabel("姓名");
QLabel* label2 = new QLabel("年龄");
QLabel*label3= new QLabel("电话");
//创建3个输入框 作为第二列
QLineEdit*edit1 = new QLineEdit();
QLineEdit*edit2 = new QLineEdit();
QLineEdit*edit3 = new QLineEdit();
//把上述控件添加到表单布局中
layout->addRow(label1,edit1);
layout->addRow(label2,edit2);
layout->addRow(label3,edit3);
//创建一个提交按钮
QPushButton *button = new QPushButton("提交");
layout->addRow(nullptr,button);//只有右侧这一列,没有左侧
connect(button,&QPushButton::clicked,this,&Widget::handl);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handl()
{
qDebug()<<"按下按钮";
}
执⾏程序, 可以看到以下结果.
6.5Spacer
使⽤布局管理器的时候, 可能需要在控件之间, 添加⼀段空白. 就可以使用 QSpacerItem 来表示
核心属性
属性 | 说明 |
---|---|
width | 宽度 |
height | 高度 |
hData | 水平⽅向的 sizePolicy QSizePolicy::Ignored : 忽略控件的尺寸,不对布局产⽣影响。 QSizePolicy::Minimum : 控件的最⼩尺寸为固定值,布局时不会超过该值。 QSizePolicy::Maximum : 控件的最⼤尺寸为固定值,布局时不会⼩于该值。 QSizePolicy::Preferred : 控件的理想尺寸为固定值,布局时会尽量接近该值 QSizePolicy::Expanding : 控件的尺寸可以根据空间调整,尽可能占据更多空间。• QSizePolicy::Shrinking : 控件的尺寸可以根据空间调整,尽可能缩⼩以适应空间。 |
vData | 垂直⽅向的 sizePolicy选项同上. |
上述属性在构造函数设置即可.
代码示例: 创建⼀组左右排列的按钮.
在界面上创建⼀个 QVBoxLayout , 并添加两个按钮
#include "widget.h"
#include "ui_widget.h"
#include<QHBoxLayout>
#include<QPushButton>
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");
//创建 spacer 使两个按钮之间存在空白
QSpacerItem*spacer = new QSpacerItem(200,20);
//把addspacer放到两个按钮之间
layout->addWidget(button1);
layout->addSpacerItem(spacer);
layout->addWidget(button2);
}
Widget::~Widget()
{
delete ui;
}
直接运行程序, 可以看到两个按钮是紧挨着的
在两个按钮中间添加⼀个 spacer
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QHBoxLayout* layout = new QHBoxLayout();
this->setLayout(layout);
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
// 创建 Spacer
QSpacerItem* spacer = new QSpacerItem(200, 20);
layout->addWidget(btn1);
// 在两个 widget 中间添加空⽩
layout->addSpacerItem(spacer);
layout->addWidget(btn2);
}
运行程序, 观察代码效果. 可以看到两个按钮之间已经存在了间隔了.调整 QSpacerItem 不同的尺寸, 即可看到不同的间距.