目录
[Push Button](#Push Button)
[Radio Button](#Radio Button)
[Check Box](#Check Box)
[LCD Number](#LCD Number)
[Calendar Widget](#Calendar Widget)
按钮类控件
Push Button
使用QPushButton表示一个按钮,QPushButton继承自QAbstractButton,这个类是一个抽象类,是其他按钮的父类。
QAbstractButton 中, 和 QPushButton 相关性较⼤的属性
属性 | 说明 |
---|---|
text | 按钮中的文本 |
icon | 按钮中的图标 |
iconSize | 按钮中图标的尺寸 |
shortCut | 按钮对应的快捷键 |
autoRepeat | 按钮是否会重复触发. 当⿏标左键按住不放时, 如果设为 true, 则会持续产⽣⿏标点击事件; 如果设为 false, 则必须释放⿏标, 再次按下⿏标时才能产⽣点击事件. (相当于游戏⼿柄上的 "连发" 效果) |
autoRepeatDelay | 重复触发的延时时间. 按住按钮多久之后, 开始重复触发 |
autoRepeatInterval | 重复触发的周期. |
设置按钮图标
cpp
// 创建图标
QIcon icon(":/doge.png");
// 设置图标
ui->pushButton->setIcon(icon);
// 设置图标⼤⼩
ui->pushButton->setIconSize(QSize(50, 50));
按钮设置快捷键
写法一:
这种方法比较不容易出错
cpp
ui->pushButton_up->setShortcut(QKeySequence(Qt::Key_W));
ui->pushButton_down->setShortcut(QKeySequence(Qt::Key_S));
ui->pushButton_left->setShortcut(QKeySequence(Qt::Key_A));
ui->pushButton_right->setShortcut(QKeySequence(Qt::Key_D));
写法二:
cpp
ui->pushButton_up->setShortcut(QKeySequence("w"));
ui->pushButton_down->setShortcut(QKeySequence("s"));
ui->pushButton_left->setShortcut(QKeySequence("a"));
ui->pushButton_right->setShortcut(QKeySequence("d"));
要设置组合快捷键的话,只需要要用 + 连接
cpp
ui->pushButton_up->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_W));
或者
cpp
ui->pushButton_right->setShortcut(QKeySequence("ctrl+d"));
设置鼠标点击按钮重复触发
键盘事件的重发触发默认开启
cpp
ui->pushButton_up->setAutoRepeat(true);
Radio Button
QRadioButton 是单选按钮. 可以让我们在多个选项中选择⼀个.
作为 QAbstractButton 和 QWidget 的⼦类, 上⾯介绍的属性和⽤法, 对于 QRadioButton
同样适⽤.
QAbstractButton 中和 QRadioButton 关系较⼤的属性
属性 | 说明 |
---|---|
checkable | 是否能选中 |
checked | 是否已经被选中,checkable是checked的前提条件 |
autoExclusive | 是否排他。 选中一个按钮是否会取消其他按钮的选中,对于QRadioButton来说默认是排他的 |
相关事件的功能:
- clicked 表⽰⼀次 "点击"
- pressed 表⽰⿏标 "按下"
- released 表⽰⿏标 "释放"
- toggled 表⽰按钮状态切换.
单选框分组
有时候一个界面需要多个单选按钮组,组和组之间不能有排他,组内部排他,因此我们引入QButtonGroup类来进行分组
// 创建三个 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);
Check Box
QCheckBox 表⽰复选按钮. 可以允许选中多个. 和 QCheckBox 最相关的属性也是 checkable 和 checked , 都是继承⾃ QAbstractButton .
⾄于 QCheckBox 独有的属性 tristate ⽤来实现 "三态复选框" .
判断是否选中
ui->check_box->ischecked();
获取多选框文本
ui->check_box->text();
显示类控件
Label
常用属性
属性 | 说明 |
---|---|
text | QLabel中的文本 |
textFormat | ⽂本的格式. • Qt::PlainText 纯⽂本 • Qt::RichText 富⽂本(⽀持 html 标签) • Qt::MarkdownText markdown 格式 • Qt::AutoText 根据⽂本内容⾃动决定⽂本格式 |
pixmap | QLabel 内部包含的图⽚. |
scaledContent | 设为 true 表⽰内容⾃动拉伸填充 QLabel 设为 false 则不会⾃动拉伸 |
alignment | 对⻬⽅式. 可以设置⽔平和垂直⽅向如何对⻬. |
wordWrap | 设为 true 内部的⽂本会⾃动换⾏. 设为 false 则内部⽂本不会⾃动换⾏. |
indent | 设置⽂本缩进. ⽔平和垂直⽅向都⽣效. |
margin | 内部⽂本和边框之间的边距. 不同于于 indent, 但是是上下左右四个⽅向都同时有效. ⽽ indent 最多只是两个⽅向有效(具体哪两个⽅向有效取决于 alignment ) |
openExternalLinks | 是否允许打开⼀个外部的链接. (当 QLabel ⽂本内容包含 url 的时候涉及到) |
buddy | 给 QLabel 关联⼀个 "伙伴" , 这样点击 QLabel 时就能激活对应的伙伴. 例如伙伴如果是⼀个 QCheckBox, 那么该 QCheckBox 就会被选中. |
设置文本格式
//第一个label设置成显示纯文本
ui->label_1->setTextFormat(Qt::PlainText);
ui->label_1->setText("这是⼀段纯⽂本");
//第二个label设置成显示富文本
ui->label_2->setTextFormat(Qt::RichText);
ui->label_2->setText("<b> 这是⼀段富⽂本 </b>");
//第三个label设置成显示 markdown
ui->label_3->setTextFormat(Qt::MarkdownText);
ui->label_3->setText("## 这是⼀段 markdown ⽂本");
给Label设置图片
//先把QLabel 设置成和窗口一样大,并且把这个QLabel左上角窗口的左上角
//让整个QLabel铺满窗口
QRect windowRect = this->geometry();
ui->label->setGeometry(0,0,windowRect.width(),windowRect.height());
QPixmap pixmap(":/1.png");
ui->label->setPixmap(pixmap);
//QLalel跟窗口一样大了,但是图片不一定,因此需要拉伸图片
ui->label->setScaledContents(true);
上述代码我们是在窗口构造函数中写的,因此我们如果再对窗口进行放大缩小,图片并不能随之变化,这里可以让Wiget窗口类,重写父类(QWidget) resize 事件 (resizeEvent虚函数)
在鼠标拖动窗口尺寸的过程中,resizeEvent虚函数会被反复调用执行,每次触发一个resizeEvent事件都会调用以此对应的虚函数,调用父类的虚函数就会实际调用子类的对应的函数(多态)
代码示例:
widget.h
cpp
#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
widget.cpp
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QLabel>
#include <QResizeEvent>
//此处的形参event是非常有用的,这里就包含了触发这个resize事件这一时刻,窗口的尺寸的数值
void Widget::resizeEvent(QResizeEvent *event)
{
ui->label->setGeometry(0,0,event->size().width(),event->size().height());
}
Label标签设置边框
设置文本对齐方式
//垂直水平居中
ui->label_1->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
Qt::AlignHCenter :水平方向上居中
Qt::AlignVCenter :垂直方向上居中
......
多个文本对齐方式之间使用 " | "
设置文本自动换行
ui->label_1->setWordWrap(true);
设置文本缩进
ui->label_1->setWordWrap(true);
ui->label_1->setIndent(50);
有多行时,每行都会产生缩进
设置边距
ui->label_1->setMargin(10);
与indent不同的是,Margin是上下左右四个方向都一样的边距
label设置伙伴
示例界面如下:
Qt中,QLabel中写的文本,是可以指定"快捷键",此处快捷键的规则功能上要比QPushButton弱很多,是在文本中使用 & 跟上一个字符来表示快捷键,比如 &A ,我们可以通过键盘上的 alt+a来触发快捷键。
绑定了伙伴关系之后,通过快捷键就可以选中对应的单选按钮/复选按钮,这里的快捷键是在文本中写 &A 类似的就可以了
LCD Number
QLCDNumber 是一个专门用来显示数字的控件,类似于"老式计算机" 的效果。
核心属性
属性 | 说明 |
---|---|
intValue | QLCDNumber 显⽰的数字值(int). |
value | QLCDNumber 显⽰的数字值(double). 和 intValue 是联动的. 例如给 value 设为 1.5, intValue 的值就是 2. 另外, 设置 value 和 intValue 的⽅法名字为 display , ⽽不是 setValue 或 者 setIntValue . |
digitCount | 显⽰⼏位数字. |
mode | 数字显⽰形式. 1. QLCDNumber::Dec :⼗进制模式,显⽰常规的⼗进制数字。 2. QLCDNumber::Hex :⼗六进制模式,以⼗六进制格式显⽰数字。 3. QLCDNumber::Bin :⼆进制模式,以⼆进制格式显⽰数字。 4. QLCDNumber::Oct :⼋进制模式,以⼋进制格式显⽰数字。 只有⼗进制的时候才能显⽰⼩数点后的内容 |
segmentStyle | 设置显⽰⻛格. 1. QLCDNumber::Flat :平⾯的显⽰⻛格,数字呈现在⼀个平坦的表⾯上。 2. QLCDNumber::Outline :轮廓显⽰⻛格,数字具有清晰的轮廓和阴影效果。 3. QLCDNumber::Filled :填充显⽰⻛格,数字被填充颜⾊并与背景区分开 |
smallDecimalPoint | 设置⽐较⼩的 ⼩数点 |
示例:倒计时
C++标准库中,没有提供定时器的实现,Boost里面提供了对应的功能
Qt中也封装了对应的定时器(结合了信号槽的机制)
QTimer 通过这个类创建出来的对象,就会产生一个timeout这样的信号,可以通过start方法来开启定时器,并且参数中设定触发timeout信号的周期,这样结合connect,把这个timeout信号绑定到需要的槽函数中,就可以执行逻辑,修改LCD Number上面的数字了
代码如下:
widget.h
cpp
#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 handle();
private:
Ui::Widget *ui;
QTimer* timer;
};
#endif // WIDGET_H
widget.cpp
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QTimer>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//初始值
ui->lcdNumber->display("10");
//创建一个QTimer实例
timer=new QTimer(this);
//把QTimer的timeout信号和咱们自己的槽函数进行连接
connect(timer,&QTimer::timeout,this,&Widget::handle);
//启动定时器,参数是触发timeout的周期,单位是ms
timer->start(1000);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handle()
{
//先拿到LCDNumber中的数字
int value=ui->lcdNumber->intValue();
if(value<=0)
{
timer->stop();
return;
}
ui->lcdNumber->display(value-1);
}
不使用QTimer的另一种写法(实际不可行)
cpp
#include "widget.h"
#include "ui_widget.h"
#include <thread>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//初始值
ui->lcdNumber->display("10");
int value=ui->lcdNumber->intValue();
while(true){
std::this_thread::sleep_for(std::chrono::seconds(1));
if(value<=0)
{
break;
}
ui->lcdNumber->display(--value);
}
}
Widget::~Widget()
{
delete ui;
}
对于GUI来说,内部包含了很多的隐藏状态,Qt为了保证修改界面的过程中,线程安全是不会受到影响的,Qt禁止了其他线程直接修改界面,因此Qt为了确保线程安全,直接要求所有的对界面的修改操作,必须在主线程中完成,对于槽函数来说,默认情况下,槽函数都是由主线程调用的。
ProgressBar
使⽤ QProgressBar 表示一个进度条
核心属性
属性 | 说明 |
---|---|
minimum | 进度条最⼩值 |
maximum | 进度条最⼤值 |
value | 进度条当前值 |
alignment | ⽂本在进度条中的对⻬⽅式 * Qt::AlignLeft : 左对⻬ * Qt::AlignRight : 右对⻬ * Qt::AlignCenter : 居中对⻬ * Qt::AlignJustify : 两端对⻬ |
textVisible | 进度条的数字是否可⻅. |
orientation | 进度条的⽅向是⽔平还是垂直 |
invertAppearance | 是否是朝反⽅向增⻓进度 |
textDirection | ⽂本的朝向. |
format | 展⽰的数字格式. 1. %p :表⽰进度的百分⽐(0-100) 2. %v :表⽰进度的数值(0-100) 3. %m :表⽰剩余时间(以毫秒为单位) 4. %t :表⽰总时间(以毫秒为单位) |
示例:进度条
代码示例:
widget.h
cpp
#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 handle();
private:
Ui::Widget *ui;
QTimer* timer;
};
#endif // WIDGET_H
widget.cpp
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QTimer>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
timer=new QTimer(this);
connect(timer,&QTimer::timeout,this,&Widget::handle);
timer->start(100);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handle()
{
int value=ui->progressBar->value();
if(value>=100)
{
timer->stop();
return;
}
ui->progressBar->setValue(value+1);
}
在上述示例代码中,widget.h中用到了QTimer,但是却没在.h文件中包含<QTimer>头文件,为啥这个代码编译不会出错?例如"找不到定义"之类的?
上述问题其实是通过Qt内部提供的一个特殊技巧来实现的,在Qt中,有一个专门的头文件,这个头文件包含了Qt中所有类的"前置声明",例如class QTimer;
Qt中问什么要使用上述的技巧,上述的技巧能解决什么问题?有啥提升呢?
主要解决的是编译速度的问题,C/C++的代码,编译速度在其他语言横向对比中,是非常慢的,因为C++编译速度慢和 #include头文件,有直接关系的,由于include关系错综复杂,因此,尽可能减少include头文件的个数,就可以有效的减少编译时间,Qt中就使用class前置声明的方式,来尽量减少头文件的包含
改变进度条的颜色
Calendar Widget
QCalendarWidget 表⽰⼀个 "⽇历" , 形如
核心属性
属性 | 说明 |
---|---|
selectDate | 当前选中的日期 |
minimumDate | 最⼩日期 |
maximumDate | 最⼤日期 |
firstDayOfWeek | 每周的第⼀天(也就是⽇历的第⼀列) 是周⼏ |
gridVisible | 是否显⽰表格的边框 |
selectionMode | 是否允许选择⽇期 |
navigationBarVisible | ⽇历上⽅标题是否显⽰ |
horizontalHeaderFormat | ⽇历上⽅标题显⽰的⽇期格式 |
verticalHeaderFormat | ⽇历第⼀列显⽰的内容格式 |
dateEditEnabled | 是否允许⽇期被编辑 |
重要信号
信号 | 说明 |
---|---|
selectionChanged(const QDate&) | 当选中的⽇期发⽣改变时发出 |
activated(const QDate&) | 当双击⼀个有效的⽇期或者按下回⻋键时发出,形参是⼀个QDate类型,保存 了选中的⽇期 |
currentPageChanged(int, int) | 当年份⽉份改变时发出,形参表⽰改变后的新年份和⽉份 |