目录
2.10. focusPolicy(设置控件获取焦点的策略)
2.11. styleSheet(通过CSS设置widget的样式)
3.1.2.2. 代码示例2:click,press,release,toggled的区别
3.2.1.3. 代码示例3:文本对齐,自动换行,缩进,边距
3.3.1.2. 代码示例2:使用正则表达式验证输入框的数据
3.3.5. DateEdit&TimeEdit&DateTimeEdit(日期&时间&时间日期的微调框)
3.6.1.1. 代码示例1:使用QVBoxLayout管理多个控件
3.6.2.1. 代码示例1:使用QHBoxLayout管理控件
3.6.3.1. 代码示例1:使用QGridLayout管理元素
3.6.4.1. 代码示例1:使用QFormLayout创建表单
1. 前言
Widget(控件)是Qt中的核心概念,控件是构成一个图形化界面的基本要素。
比如说QtCreator创建项目之后的窗口,用到的就有按钮,树形视图,列表视图,单行输入框,多行输入框等等,这些都是控件。
Qt作为⼀个成熟的GUI开发框架,内置了⼤量的常⽤控件.这⼀点在QtDesigner中就可以看到端倪.并且Qt也提供了"⾃定义控件"的能⼒,可以让程序猿在现有控件不能满⾜需求的时候,对现有控件做出扩展,或者⼿搓出新的控件.
2. QWidget核心属性
在Qt中,使用QWidget类表示"控件",像按钮,视图,输入框,滚动条等具体的控件类,都是继承自QWidget。可以说是,QWidget中就包含了Qt整个控件体系中通用的部分。
在QtDesigner中,随便拖一个控件过来,选中该控件,即可在右下方看到QWidget中的属性。
这些属性既可以通过QtDesigner直接修改,也可以通过代码的方式修改。
2.1. enabled(控件是否可用)
描述了一个控件是否处于可用的状态。
API | 说明 |
isEnabled() | 获取到控件的可⽤状态. |
setEnabled | 设置控件是否可使⽤.true表⽰可⽤,false表⽰禁⽤ |
所谓的禁用指的是该控件不能接收任何用户的输入事件,并且外观上往往是灰色的。
如果一个widget被禁用,则该widget的子元素也被禁用
代码示例:使用代码创建一个禁用状态的按钮
#include"widget.h"
#include"ui_widget.h"
#include<QPushButton>
#include<QDebug>
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
QPushButton*btn=newQPushButton(this);
btn->setText("button");
btn->setEnabled(false);//此时按钮就处于禁用状态。
}
Widget::~Widget()
{
deleteui;
}
运行程序,可以看到按钮是灰色的,不能被点击。
代码示例:通过按钮2切换按钮1的禁用状态
- 使用QtDesigner拖两个按钮到Widget中
两个按钮的objectName分别为pushButton和pushButton_2
2.生成两个按钮的slot函数
- 使用isEnabled获取当前按钮的状态
- 使用setEnabled修改按钮的可用状态,此处是直接针对原来的可用状态进行取反后设置。
#include"widget.h"
#include"ui_widget.h"
#include<QDebug>
#include<QPushButton>
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
deleteui;
}
voidWidget::on_pushButton_clicked()
{
qDebug()<<"点击按钮";
}
voidWidget::on_pushButton_2_clicked()
{
boolenable=this->ui->pushButton->isEnabled();
if(enable)
{
this->ui->pushButton->setEnabled(false);
}
else
{
this->ui->pushButton->setEnabled(true);
}
}
运⾏程序,可以看到,初始情况下,上⾯的按钮是可⽤状态.
点击下⽅按钮,即可使上⽅按钮被禁⽤;再次点击下⽅按钮,上⽅按钮就会解除禁⽤.(禁⽤状态的按钮为灰⾊,且不可点击).
2.2. geometry(尺寸)
位置和尺寸,其实是四个属性的统称
- x横坐标
- y纵坐标
- width宽度
- height高度
但是实际开发中,我们并不会直接使⽤这⼏个属性,⽽是通过⼀系列封装的⽅法来获取/修改.
对于Qt的坐标系,不要忘记是⼀个"左⼿坐标系".其中坐标系的原点是当前元素的⽗元素的左上⻆
API | 说明 |
geometry() | 获取到控件的位置和尺⼨.返回结果是⼀个QRect,包含了x,y,width,height.其 |
setGeometry(QRect) | 设置控件的位置和尺⼨.可以直接设置⼀个QRect,也可以分四个属性单独设置. |
代码示例:控制按钮的位置
在界⾯中拖五个按钮.五个按钮的objectName分别为pushButton_target,pushButton_up,
pushButton_down,pushButton_left,pushButton_right五个按钮的初始位置和⼤⼩都随意.
在widget.cpp中编写四个按钮的slot函数
#include"test.h"
#include"ui_test.h"
#include<QPushButton>
#include<QDebug>
test::test(QWidget*parent)
:QWidget(parent)
,ui(newUi::test)
{
ui->setupUi(this);
}
test::~test()
{
deleteui;
}
voidtest::on_pushButton_up_clicked()
{
QRectrect=ui->pushButton_target->geometry();
qDebug()<<rect;
rect.setY(rect.y()-5);
ui->pushButton_target->setGeometry(rect);
}
voidtest::on_pushButton_left_clicked()
{
QRectrect=ui->pushButton_target->geometry();
qDebug()<<rect;
rect.setX(rect.x()-5);
ui->pushButton_target->setGeometry(rect);
}
voidtest::on_pushButton_down_clicked()
{
QRectrect=ui->pushButton_target->geometry();
qDebug()<<rect;
rect.setY(rect.y()+5);
ui->pushButton_target->setGeometry(rect);
}
voidtest::on_pushButton_right_clicked()
{
QRectrect=ui->pushButton_target->geometry();
qDebug()<<rect;
rect.setX(rect.x()+5);
ui->pushButton_target->setGeometry(rect);
}
运⾏程序,可以看到,按下下⽅的四个按钮,就会控制target的左上⻆的位置.对应的按钮整个尺⼨也会发⽣改变.
上述代码中我们是直接设置的QRect中的x,y.实际上QRect内部是存储了左上和右下两个点的坐标,再通过这两个点的坐标差值计算⻓宽.单纯修改左上坐标就会引起整个矩形的⻓宽发⽣改变.
2.2.1. windowframe的影响
如果widget作为⼀个窗⼝(带有标题栏,最⼩化,最⼤化,关闭按钮),那么在计算尺⼨和坐标的
时候就有两种算法.包含windowframe和不包含windowframe.
其中x(),y(),frameGeometry(),pos(),move()都是按照包含windowframe的⽅式来计算
的.
其中geometry(),width(),height(),rect(),size()则是按照不包含windowframe的⽅式来计
算的.
当然,如果⼀个不是作为窗⼝的widget,上述两类⽅式得到的结果是⼀致的.
相关API
API | 说明 |
x() | 获取横坐标 |
y() | 获取纵坐标 |
pos() | 返回QPoint对象,⾥⾯包含x(),y(),setX(),setY()等⽅法. |
frameSize() | 返回QSize对象,⾥⾯包含width(),height(),setWidth(),setHeight()等⽅法. |
frameGeometry() | 返回QRect对象.QRect相当于QPoint和QSize的结合体.可以获取x,y, |
width() | 获取宽度 |
height() | 获取⾼度 计算时不包含windowframe |
size() | 返回QSize对象,⾥⾯包含width(),height(),setWidth(),setHeight()等⽅法. |
rect() | 返回QRect对象.QRect相当于QPoint和QSize的结合体.可以获取并设置x, |
geometry() | 返回QRect对象.QRect相当于QPoint和QSize的结合体.可以获取x,y, |
setGeometry() | 直接设置窗⼝的位置和尺⼨.可以设置x,y,width,height,或者QRect对象. |
代码示例:将geometry和frameGeometry打印出来感受一下
#include"test.h"
#include"ui_test.h"
#include<QPushButton>
#include<QDebug>
test::test(QWidget*parent)
:QWidget(parent)
,ui(newUi::test)
{
ui->setupUi(this);
QRectrect1=this->geometry();
QRectrect2=this->frameGeometry();
qDebug()<<rect1;
qDebug()<<rect2;
}
test::~test()
{
deleteui;
}
voidtest::on_pushButton_clicked()
{
qDebug()<<"1";
QRectrect1=this->geometry();
QRectrect2=this->frameGeometry();
qDebug()<<rect1;
qDebug()<<rect2;
}
在初始的时候是一样的,点击按钮之和,发生了变化。
🏝注意!
在构造⽅法中,Widget刚刚创建出来,还没有加⼊到对象树中.此时也就不具备Window
frame.
在按钮的slot函数中,由于⽤⼾点击的时候,对象树已经构造好了,此时Widget已经具备了
Windowframe,因此在位置和尺⼨上均出现了差异.
如果把上述代码修改成打印pushButton的geometry和frameGeometry,结果就是完全相
同的.因为pushButton并⾮是⼀个窗⼝
2.3. windowTitle(窗口标题)
API | 说明 |
windowTitle() | 获取到控件的窗⼝标题. |
setWindowTitle(const | 设置控件的窗⼝标题. |
🍰注意!上述设置操作针对不同的widget可能会有不同的⾏为.
如果是顶层widget(独⽴窗⼝),这个操作才会有效.
如果是⼦widget,这个操作⽆任何效果.
代码示例:设置窗口标题
#include"test.h"
#include"ui_test.h"
#include<QPushButton>
#include<QDebug>
test::test(QWidget*parent)
:QWidget(parent)
,ui(newUi::test)
{
ui->setupUi(this);
this->setWindowTitle("这是一个窗口标题");
}
test::~test()
{
deleteui;
}
test::test(QWidget*parent)
:QWidget(parent)
,ui(newUi::test)
{
ui->setupUi(this);
this->setWindowTitle("这是一个窗口标题");
QPushButton*btn=newQPushButton(this);
btn->setText("按钮");
btn->setWindowTitle("这是一个按钮窗口");
}
windowTitle属性,只能针对顶层的widget才能生效。当前不应该给按钮设置windowTitle,但是实际设置了之和,没有任何效果,也没有报错。还是希望当代码写的不太科学的时候,能给出一些报错提示。
2.4. windowIcon(窗口图标)
API | 说明 |
windowIcon() | 获取到控件的窗⼝图标.返回QIcon对象. |
setWindowIcon(const | 设置控件的窗⼝图标. |
🎹同windowTitle,上述操作仅针对顶层widget有效.
代码示例:将上面的图片设置为窗口的图标
#include"test.h"
#include"ui_test.h"
#include<QPushButton>
#include<QDebug>
#include<QIcon>
test::test(QWidget*parent)
:QWidget(parent)
,ui(newUi::test)
{
ui->setupUi(this);
QIconicon("C:/Users/Lenovo/Pictures/1664844094688.png.jpg");
this->setWindowIcon(icon);
}
test::~test()
{
deleteui;
}
如果说上面的代码路径出错或者图片被删了,就会导入图片加载不出来。
对此Qt引入了qrc机制,这个机制就是从根本上解决上述两个问题的。确保图片所在的路径在目标用户机器上存在,确保图片不会被搞没了。给Qt项目引入一个额外的xml文件(后缀名使用.qrc表示)在这个xml中要把使用的图片资源给导入进来,并且在xml中进行记录。Qt在编译项目的时候,就会根据qrc中描述的图片信息,找到图片内容,并且提取出图片的二进制数据,把这些二进制数据转成C++代码,最终编译到exe里。
当然这个机制也是有缺点的,无法导入太大的资源文件,比如搞几个gb这种视频文件,qrc就无能为力了。
2.5. 使用qrc文件资源管理
代码示例:通过qtc管理图片作为图标
创建一个QtResourceFile(qrc文件),文件名随意起(不能有中文),
添加之后会得到一个这样的页面
在qrc编辑器中,添加前缀(点击AddPrefix)
这里我们把前缀设置为/即可。
所谓的前缀,可以理解成"⽬录".这个前缀决定了后续我们如何在代码中访问资源.
在资源编辑器中,点击addDiles添加资源文件,此处我们把上面的图片给添加进去。
在添加图片之前,要确保导入的图片必须在resource.qrc文件的同级目录,或者同级目录的子目录里面。
添加完毕后,可以在资源编辑器中看到添加好的⽂件
在代码中使用这张图片。
#include"test.h"
#include"ui_test.h"
#include<QPushButton>
#include<QDebug>
#include<QIcon>
test::test(QWidget*parent)
:QWidget(parent)
,ui(newUi::test)
{
ui->setupUi(this);
QIconicon(":/1664844094688.png.jpg");
this->setWindowIcon(icon);
}
test::~test()
{
deleteui;
}
使用:作为开头,表示从qrc中读取资源,
/是上面配置的前缀
1664844094688.png.jpg是资源的名称
接下来,我们可以进⼊到项⽬的构建⽬录,可以看到,⽬录中多了⼀个qrc_resource.cpp⽂件.直
接打开这个⽂件,可以看到类似如下代码:
上述代码其实就是通过unsignedchar数组,把rose.jpg中的每个字节都记录下来.这些代码会被编译到exe中.后续⽆论exe被复制到哪个⽬录下,都确保能够访问到该图⽚资源.
2.6. windowOpacity(半透明效果)
API | 说明 |
windowOpacity() | 获取到控件的不透明数值.返回float,取值为0.0->1.0其中0.0表⽰全透明,1.0表⽰完全不透明. |
setWindowOpacity(floatn) | 设置控件的不透明数值. |
代码示例:调整按钮透明度
- 在界面上拖放两个按钮,分别用来表示按钮,增加透明度,减少透明度
objectName为pushButton_add,pushButton_sub。
- 编写cpp函数,点击sub会减少透明度,点击add会增加透明度。
#include"test.h"
#include"ui_test.h"
#include<QPushButton>
#include<QDebug>
#include<QIcon>
test::test(QWidget*parent)
:QWidget(parent)
,ui(newUi::test)
{
ui->setupUi(this);
}
test::~test()
{
deleteui;
}
voidtest::on_pushButton_add_clicked()
{
floatopacity=this->windowOpacity();
if(opacity>=1.0)return;
qDebug()<<opacity;
opacity+=0.1;
this->setWindowOpacity(opacity);
}
voidtest::on_pushButton_sub_clicked()
{
floatopacity=this->windowOpacity();
if(opacity<=0.0)return;
qDebug()<<opacity;
opacity-=0.1;
this->setWindowOpacity(opacity);
}
注意,C++中float类型遵守IEEE754标准,因此在进⾏运算的时候会有⼀定的精度误差.因此1-0.1的数值并⾮是0.9.
2.7. cursor(设置鼠标光标)
API | 说明 |
cursor() | 获取到当前widget的cursor属性,返回QCursor对象. |
setCursor(constQCursor&cursor) | 设置该widget光标的形状.仅在⿏标停留在该widget上时⽣效. |
QGuiApplication::setOverrideCursor(constQCursor&cursor) | 设置全局光标的形状.对整个程序中的所有widget都会⽣效.覆盖上⾯的setCursor设置的内容. |
代码示例:设置按钮的光标
在Designer中拖出来一个按钮,然后在cpp文件中设置点击按钮之后的光标。
#include"test.h"
#include"ui_test.h"
#include<QPushButton>
#include<QDebug>
#include<QIcon>
test::test(QWidget*parent)
:QWidget(parent)
,ui(newUi::test)
{
ui->setupUi(this);
}
test::~test()
{
deleteui;
}
voidtest::on_pushButton_clicked()
{
QCursorcursor(Qt::WaitCursor);
ui->pushButton->setCursor(cursor);
}
emm,截图失败,请自行演示。
系统内置的光标形状如下:
Ctrl+左键点击Qt::WaitCursor跳转到源码即可看到。
enumCursorShape{
ArrowCursor,
UpArrowCursor,
CrossCursor,
WaitCursor,
IBeamCursor,
SizeVerCursor,
SizeHorCursor,
SizeBDiagCursor,
SizeFDiagCursor,
SizeAllCursor,
BlankCursor,
SplitVCursor,
SplitHCursor,
PointingHandCursor,
ForbiddenCursor,
WhatsThisCursor,
BusyCursor,
OpenHandCursor,
ClosedHandCursor,
DragCopyCursor,
DragMoveCursor,
DragLinkCursor,
LastCursor=DragLinkCursor,
BitmapCursor=24,
CustomCursor=25
};
当然也可以使用自定义的光标。
#include"test.h"
#include"ui_test.h"
#include<QPushButton>
#include<QDebug>
#include<QIcon>
#include<QPixmap>
test::test(QWidget*parent)
:QWidget(parent)
,ui(newUi::test)
{
ui->setupUi(this);
//创建一个位图对象,加载自定义光标图片
QPixmappixmap(":/1664844094688.png.jpg");
//缩放图片为64*64的尺寸
pixmap=pixmap.scaled(64,64);
//创建QCursor对象,并指定热点为(2,2)坐标位置
//所谓热点就是鼠标点击时生效的位置
QCursorcursor(pixmap,2,2);
//设置光标
this->setCursor(cursor);
}
test::~test()
{
deleteui;
}
截图失败,在载入qrc资源后自行测试。
2.8. font(字体)
API | 说明 |
font() | 获取当前widget的字体信息.返回QFont对象. |
setFont(constQFont&font) | 设置当前widget的字体信息. |
关于QFont
属性 | 说明 |
family | 字体家族.⽐如"楷体","宋体","微软雅⿊"等. |
pointSize | 字体⼤⼩ |
weight | 字体粗细.以数值⽅式表⽰粗细程度取值范围为[0,99],数值越⼤,越 |
bold | 是否加粗.设置为true,相当于weight为75.设置为false相当于 |
italic | 是否倾斜 |
underline | 是否带有下划线 |
strikeOut | 是否带有删除线 |
代码示例:使用代码设置字体属性
在界⾯上创建⼀个label
如果你想使用Designer来设置字体属性,可以在ui中的右下角找到font属性,修改font中的属性,就可以完成对自己的改变了。
在cpp文件中对label进行修改
#include"test.h"
#include"ui_test.h"
#include<QPushButton>
#include<QDebug>
#include<QIcon>
#include<QPixmap>
#include<QFont>
test::test(QWidget*parent)
:QWidget(parent)
,ui(newUi::test)
{
ui->setupUi(this);
//设置label的文本内容
ui->label->setText("这是一段文本");
//创建字体对象
QFontfont;
//设置字体家族
font.setFamily("宋体");
//设置字体大小
font.setPointSize(20);
//设置字体加粗
font.setBold(true);
//设置字体倾斜
font.setItalic(true);
//设置字体下划线
font.setUnderline(true);
//设置字体删除线
font.setStrikeOut(true);
//设置自己对象到label上
ui->label->setFont(font);
}
test::~test()
{
deleteui;
}
2.9. toolTip(鼠标悬停说明)
API | 说明 |
setToolTip | 设置toolTip. |
setToolTipDuring | 设置toolTip提⽰的时间.单位ms. |
toolTip只是给⽤⼾看的.在代码中⼀般不需要获取到toolTip.
代码⽰例:设置按钮的toolTip
1)在界⾯上拖放两个按钮.objectName设置为pushButton_yes和pushButton_no
2)编写test.cpp
#include"test.h"
#include"ui_test.h"
#include<QPushButton>
#include<QDebug>
#include<QIcon>
#include<QPixmap>
#include<QFont>
test::test(QWidget*parent)
:QWidget(parent)
,ui(newUi::test)
{
ui->setupUi(this);
ui->pushButton_yes->setToolTip("这是一个yes");
ui->pushButton_yes->setToolTipDuration(3000);
ui->pushButton_no->setToolTip("这是一个no");
ui->pushButton_no->setToolTipDuration(3000);
}
test::~test()
{
deleteui;
}
系统截图⽆法截取到⿏标光标
2.10. focusPolicy(设置控件获取焦点的策略)
设置控件获取到焦点的策略.⽐如某个控件能否⽤⿏标选中或者能否通过tab键选中.
所谓"焦点",指的就是能选中这个元素.接下来的操作(⽐如键盘操作),就都是针对该焦点元素进⾏的了.这个对于输⼊框,单选框,复选框等控件⾮常有⽤的.
API | 说明 |
focusPolicy() | 获取该widget的focusPolicy,返回Qt::FocusPolicy |
setFocusPolicy(Qt::FocusPolicypolicy) | 设置widget的focusPolicy. |
Qt::FocusPolicy是⼀个枚举类型.取值如下
•Qt::NoFocus:控件不会接收键盘焦点
•Qt::TabFocus:控件可以通过Tab键接收焦点
•Qt::ClickFocus:控件在⿏标点击时接收焦点
•Qt::StrongFocus:控件可以通过Tab键和⿏标点击接收焦点(默认值)
•Qt::WheelFocus:类似于Qt::StrongFocus,同时控件也通过⿏标滚轮获取到焦点(新增
的选项,⼀般很少使⽤).
代码⽰例:理解不同的focusPolicy
1)在界⾯上创建四个单⾏输⼊框(LineEdit)
2)修改四个输⼊框的focusPolicy属性为Qt::StrongFocus(默认取值,⼀般不⽤额外修改)
此时运⾏程序,可以看到,使⽤⿏标单击/tab,就可以移动光标所在输⼊框.从⽽接下来的输⼊就是针对这个获取焦点的输⼊框展开的了.
3)修改第⼆个输⼊框的focusPolicy为Qt::NoFocus,则第⼆个输⼊框不会被tab/⿏标左键选中.
此时这个输⼊框也就⽆法输⼊内容了.
4)修改第⼆个输⼊框focusPolicy为Qt::TabFocus,则只能通过tab选中,⽆法通过⿏标选
中.
5)修改第⼆个输⼊框focusPolicy为Qt::ClickFocus,则只能通过tab选中,⽆法通过⿏标
选中.
2.11. styleSheet(通过CSS设置widget的样式)
🎨CSS(CascadingStyleSheets层叠样式表)本⾝属于⽹⻚前端技术.主要就是⽤来描述界⾯的样式.所谓"样式",包括不限于⼤⼩,位置,颜⾊,间距,字体,背景,边框等.
我们平时看到的丰富多彩的⽹⻚,就都会⽤到⼤量的CSS.Qt虽然是做GUI开发,但实际上和⽹⻚前端有很多异曲同⼯之处.因此Qt也引⼊了对于CSS的⽀持.
CSS中可以设置的样式属性⾮常多.基于这些属性Qt只能⽀持其中⼀部分,称为QSS(QtStyleSheet)
此处只是进⾏⼀个简单的演⽰.
代码⽰例:设置⽂本样式
1)在界⾯上创建label
2)编辑右侧的styleSheet属性,设置样式
此处的语法格式同CSS,使⽤键值对的⽅式设置样式.其中键和值之间使⽤:分割.键值对之间使⽤;分割.另外,QtDesigner只能对样式的基本格式进⾏校验,不能检测出哪些样式不被Qt⽀持.⽐如textalign:center这样的⽂本居中操作,就⽆法⽀持.
编辑完成样式之后,可以看到在QtDesigner中能够实时预览出效果.
3)运⾏程序,可以看到实际效果和预览效果基本⼀致
3. 常用控件
Qt中提供的各种控件都继承与QWidget,所以上面说的QWidget中设计到的各种函数,对于下面的各种控件都是有效的。
在学C/C++的时候,应该是了解过抽象类的,抽象类包含了纯虚函数,无法创建出实例对象,要创建出实例对象,就得创建子类,重写虚函数。
3.1. 按钮类控件
3.1.1. PushButton(普通按钮)
使用QPushButton表示一个按钮,QPushButton继承于QAbstractButton,这个类是一个抽象类,是其他按钮的父类。
在QtDesigner中也能看到这里的继承关系。
QAbstractButton中,和QPushButton相关性较⼤的属性。
属性 | 说明 |
text | 按钮中的⽂本 |
icon | 按钮中的图标 |
iconSize | 按钮中图标的尺⼨ |
shortCut | 按钮对应的快捷键 |
autoRepeat | 按钮是否会重复触发.当⿏标左键按住不放时, |
autoRepeatDelay | 重复触发的延时时间.按住按钮多久之后,开始重复触发. |
autoRepeatInterval | 重复触发的周期. |
- QAbstractButton作为QWidget的⼦类,当然也继承了QWidget的属性.上⾯
介绍的QWidget⾥的各种属性⽤法,对于QAbstractButton同样适⽤.因此表格仅
列出QAbstractButton独有的属性. - Qt的api设计⻛格是⾮常清晰的.此处列出的属性都是可以获取和设置的.例如,使
⽤text()获取按钮⽂本;使⽤setText()设置⽂本.
事实上,QPushButton的核⼼功能都是QAbstractButton提供的.⾃⾝提供的属性都⽐较简单.其中default和audoDefault影响的是按下enter时⾃动点击哪个按钮的⾏为;flat把按钮设置为扁平的样式.这⾥我们暂时都不做过多关注.
3.1.1.1. 示例1:带有图标的按钮
- 创建qrc文件,并导入图片
- 在界面上创建一个按钮
- 修改widget.cpp,给按钮设置图标
test::test(QWidget*parent)
:QWidget(parent)
,ui(newUi::test)
{
ui->setupUi(this);
QIconicon(":/1664844094688.png.jpg");
ui->pushButton->setIcon(icon);
ui->pushButton->setIconSize(QSize(50,50));
}
- 执行程序,观察效果
3.1.1.2. 示例2:带有快捷键的按钮
- 在界面中拖五个按钮
objectName分别为:pushButton_target/left/right/up/low
- 创建qrc,并导入五个图片
- 修改widget.cpp,设置图标资源和快捷键
使用setShortcut给按钮设置快捷键,参数是一个QKeySequence对象,表示一个按键序列,支持组合键。
QKeySequence的构造函数参数,可以直接使用ctrl+c这样的案件名字符串表示,也可以使用预定义好的常量如(Qt::CTRL+Qt::Key_C)表示。
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->pushButton_target->setIcon(QIcon(":/1664844094688.png.jpg"));
ui->pushButton_target->setIconSize(QSize(80,80));
ui->pushButton_up->setIcon(QIcon(":/up.png"));
ui->pushButton_up->setIconSize(QSize(80,80));
ui->pushButton_low->setIcon(QIcon(":/down.png"));
ui->pushButton_low->setIconSize(QSize(80,80));
ui->pushButton_left->setIcon(QIcon(":/left.png"));
ui->pushButton_left->setIconSize(QSize(80,80));
ui->pushButton_right->setIcon(QIcon(":/right.png"));
ui->pushButton_right->setIconSize(QSize(80,80));
//ui->pushButton_up->setShortcut(QKeySequence("w"));
//ui->pushButton_low->setShortcut(QKeySequence("s"));
//ui->pushButton_left->setShortcut(QKeySequence("a"));
//ui->pushButton_right->setShortcut(QKeySequence("d"));
ui->pushButton_up->setShortcut(QKeySequence(Qt::Key_W));
ui->pushButton_low->setShortcut(QKeySequence(Qt::Key_S));
ui->pushButton_left->setShortcut(QKeySequence(Qt::Key_A));
ui->pushButton_right->setShortcut(QKeySequence(Qt::Key_D));
}
- 修改widget.cpp,设置四个方向键的slot函数
voidWidget::on_pushButton_left_clicked()
{
QRectrect=ui->pushButton_target->geometry();
ui->pushButton_target->setGeometry(rect.x()-5,rect.y(),rect.width(),rect.height());
}
voidWidget::on_pushButton_up_clicked()
{
QRectrect=ui->pushButton_target->geometry();
ui->pushButton_target->setGeometry(rect.x(),rect.y()-5,rect.width(),rect.height());
}
voidWidget::on_pushButton_low_clicked()
{
QRectrect=ui->pushButton_target->geometry();
ui->pushButton_target->setGeometry(rect.x(),rect.y()+5,rect.width(),rect.height());
}
voidWidget::on_pushButton_right_clicked()
{
QRectrect=ui->pushButton_target->geometry();
ui->pushButton_target->setGeometry(rect.x()+5,rect.y(),rect.width(),rect.height());
}
- 运行程序,此时点击按钮,或使用wasd就可以让图片移动了。
- 按钮的重复触发
上面的例子中,按快捷键是可以重复触发的,但是鼠标点击不能。修改widget函数,在构造函数中开启重复触发。
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->pushButton_target->setIcon(QIcon(":/1664844094688.png.jpg"));
ui->pushButton_target->setIconSize(QSize(80,80));
ui->pushButton_up->setIcon(QIcon(":/up.png"));
ui->pushButton_up->setIconSize(QSize(80,80));
ui->pushButton_low->setIcon(QIcon(":/down.png"));
ui->pushButton_low->setIconSize(QSize(80,80));
ui->pushButton_left->setIcon(QIcon(":/left.png"));
ui->pushButton_left->setIconSize(QSize(80,80));
ui->pushButton_right->setIcon(QIcon(":/right.png"));
ui->pushButton_right->setIconSize(QSize(80,80));
//ui->pushButton_up->setShortcut(QKeySequence("w"));
//ui->pushButton_low->setShortcut(QKeySequence("s"));
//ui->pushButton_left->setShortcut(QKeySequence("a"));
//ui->pushButton_right->setShortcut(QKeySequence("d"));
ui->pushButton_up->setShortcut(QKeySequence(Qt::Key_W));
ui->pushButton_low->setShortcut(QKeySequence(Qt::Key_S));
ui->pushButton_left->setShortcut(QKeySequence(Qt::Key_A));
ui->pushButton_right->setShortcut(QKeySequence(Qt::Key_D));
ui->pushButton_up->setAutoRepeat(true);
ui->pushButton_left->setAutoRepeat(true);
ui->pushButton_right->setAutoRepeat(true);
ui->pushButton_low->setAutoRepeat(true);
}
3.1.2. RadioButton(单选按钮)
QRadioButton是单选按钮,可以让我们在多个选项中选择一个。
作为QAbstractButton和QWidget的子类,上面介绍的函数,对于QRadioButton一样使用。
QAbstractButton中和QRadioButton关系较大的属性
属性 | 说明 |
checkable | 是否能选中 |
checked | 是否已经被选中.checkable是checked的前提条件. |
autoExclusive | 是否排他. |
3.1.2.1. 代码示例1:选择技术
- 在界面上创建一个label,和n个单选按钮
三个单选按钮的objectName分别为radioButton_java/python/c++/php/go
- 修改widget.cpp,编辑三个QRadioButton的slot函数.
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->radioButton_c->setChecked(true);//默认选项
//如果将true改为false
ui->label->setText("技术;c++");
}
voidWidget::on_radioButton_java_clicked()
{
ui->label->setText("技术:java");
}
voidWidget::on_radioButton_python_clicked()
{
ui->label->setText("技术:python");
}
voidWidget::on_radioButton_c_clicked()
{
ui->label->setText("技术:c++");
}
voidWidget::on_radioButton_other_clicked()
{
ui->label->setText("技术:other");
}
使用setEnabled可以彻底禁用按钮。
3.1.2.2. 代码示例2:click,press,release,toggled的区别
- clicked表⽰⼀次"点击"
- pressed表⽰⿏标"按下"
- released表⽰⿏标"释放"
- toggled表⽰按钮状态切换
- 在界面上创建四个单选按钮,objectName分别为radioButton_1/2/3/4
- 给1创建clicked槽函数,给2创建pressed槽函数,给3创建released槽函数,给4创建toggled槽函数
voidWidget::on_radioButton_1_clicked(boolchecked)
{
qDebug()<<"clicked"<<checked;
}
voidWidget::on_radioButton_2_pressed()
{
qDebug()<<"pressed";
}
voidWidget::on_radioButton_3_released()
{
qDebug()<<"released";
}
voidWidget::on_radioButton_4_toggled(booltoggled)
{
qDebug()<<"toggled"<<toggled;
}
- 运行程序可以看到
clicked是一次鼠标按下+释放触发的
pressed是鼠标按下触发的
released是鼠标释放触发的
toggled是checked属性改变时触发的
3.1.2.3. 代码示例3:单选框分组
- 在界面上创建6个单选框,用来模拟麦当劳点餐界面,objectName分别为radioButton到radioButton_6
此时直接运行程序,可以看到这6个QadioButton之间都是排他的。
- 引入QButtonGroup进行分组
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
QButtonGroup*group1=newQButtonGroup();
QButtonGroup*group2=newQButtonGroup();
QButtonGroup*group3=newQButtonGroup();
group1->addButton(ui->radioButton_1);
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);
}
再次执行程序,就可以看到组与组之间能够完成排他了。
3.1.3. CheckBox(复选按钮)
QCheckBox表示复选按钮,可以允许选中多个。和QCheckBox下才能过关的属性是checkable和checked,都是继承于QAstractButton,QCheckBox独有的属性tristate用来实现"三态复选框"
3.1.3.1. 代码示例:获取复选按钮的取值
- 在界面上创建三个复选按钮,和一个普通按钮,objectName分别为checkBox_eat/sleep/play和pushButton
- 给pushButton添加slot函数
voidWidget::on_pushButton_clicked()
{
QStringret="今日安排";
if(ui->checkBox_play->isChecked())
{
ret+=ui->checkBox_play->text();
}
if(ui->checkBox_eat->isChecked())
{
ret+=ui->checkBox_eat->text();
}
if(ui->checkBox_sleep->isChecked())
{
ret+=ui->checkBox_sleep->text();
}
ui->label->setText(ret);
}
- 运行程序
3.2. 显示类控件
3.2.1. Label(显示文本和图片)
QLabel可以用来显示文本和图片。
属性 | 说明 |
text | QLabel中的⽂本 |
textFormat | ⽂本的格式. |
pixmap | QLabel内部包含的图⽚. |
scaledContents | 设为true表⽰内容⾃动拉伸填充QLabel |
alignment | 对⻬⽅式. |
wordWrap | 设为true内部的⽂本会⾃动换⾏. |
indent | 设置⽂本缩进.⽔平和垂直⽅向都⽣效. |
margin | 内部⽂本和边框之间的边距. |
openExternalLinks | 是否允许打开⼀个外部的链接. |
buddy | 给QLabel关联⼀个"伙伴",这样点击QLabel时就能激活对应的伙伴. |
3.2.1.1. 代码示例1:显示不同格式的文本
- 在界面上创建三个QLabel,尺寸放大一些,objectName分别为label_1/2/3
- 修改widget.cpp,设置三个label属性
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->label_1->setTextFormat(Qt::PlainText);
ui->label_1->setText("这是纯文本");
ui->label_2->setTextFormat(Qt::RichText);
ui->label_2->setText("<b>这是一段富文本<b/>");
ui->label_3->setTextFormat(Qt::MarkdownText);
ui->label_3->setText("#这是一段Markdown文本");
}
- 运行程序
3.2.1.2. 代码示例2:显示图片
- 在界面上创建一个QLabel并创建qrc文件,把要显示的文件导入到qrc中
- 修改widget.cpp文件
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->label->setGeometry(0,0,800,600);
QPixmappixmap(":/1664844094688.png.jpg");
ui->label->setPixmap(pixmap);
}
- 运行程序
- 通过scaledContents把QLabel填充满
ui->label->setScaledContents(true);
- 此时拖动窗口大小,图片并不会随着发生变化,可以在Widget中重写resizeEvent函数,解决这个问题
#include<QResizeEvent>
#include<QSize>
voidWidget::resizeEvent(QResizeEvent*event)
{
//可以直接通过this->width()和this->height()设置label新的尺⼨,也可以通过
//event参数拿到新的尺⼨.
//ui->label->setGeometry(0,0,this->width(),this->height());
ui->label->setGeometry(0,0,event->size().width(),event->size().height());
qDebug()<<event->size();
}
此处的resizeEvent函数我们没有⼿动调⽤,但是能在窗⼝⼤⼩变化时被⾃动调⽤.这个过程就是依赖C++中的多态来实现的.Qt框架内部管理着QWidget对象表⽰咱们的窗⼝.在窗⼝⼤⼩发⽣改变时,Qt就会⾃动调⽤resizeEvent函数.但是由于实际上这个表⽰窗⼝的并⾮是QWidget,⽽是QWidget的⼦类,也就是咱们⾃⼰写的Widget.此时虽然是通过⽗类调⽤函数,但是实际上执⾏的是⼦类的函数(也就是我们重写后的resizeEvent).此处属于是多态机制的⼀种经典⽤法.通过上述过程,就可以把⾃定义的代码,插⼊到框架内部执⾏.相当于"注册回调函数".
3.2.1.3. 代码示例3:文本对齐,自动换行,缩进,边距
- 创建4个label,objectName分别为label_1/2/3/4,并在QFrame中设置frameShape为Box
QFrame是QLabel的⽗类.其中frameShape属性⽤来设置边框性质.
QFrame::Box:矩形边框
QFrame::Panel:带有可点击区域的⾯板边框
QFrame::WinPanel:Windows⻛格的边框
QFrame::HLine:⽔平线边框
QFrame::VLine:垂直线边框
QFrame::StyledPanel:带有可点击区域的⾯板边框,但样式取决于窗⼝主题
- 修改widget.cpp文件
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->label_1->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
ui->label_1->setText("垂直+水平居中的文本");
ui->label_2->setWordWrap(true);
ui->label_2->setText("这是一段会自动换行的文本|这是一段会自动换行的文本|这是一段会自动换行的文本|这是一段会自动换行的文本");
ui->label_3->setIndent(50);
ui->label_3->setText("这是一段会自动缩进的文本");
ui->label_4->setMargin(20);
ui->label_4->setText("这是设置边距的文本");
}
- 执行代码
3.2.1.4. 代码示例4:设置伙伴
- 创建两个label和两个radioButton,objectName分别为label_1/2,radioButton_1/2
此处把label中的⽂本设置为"快捷键&A"这样的形式.
其中&后⾯跟着的字符,就是快捷键.
可以通过alt+A的⽅式来触发该快捷键.
但是注意,这⾥的快捷键和QPushButton的不同.需要搭配alt和单个字⺟的⽅式才能触发.
- 编写widget.cpp
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
//设置radioButton和label的伙伴关系
ui->label_1->setBuddy(ui->radioButton_1);
ui->label_2->setBuddy(ui->radioButton_2);
}
- 执行代码
3.2.2. LCDNumber(专门用来显示数字)
QLCDNumber是一个专门用来显示数字的控件。
属性 | 说明 |
intValue | QLCDNumber显⽰的数字值(int). |
value | QLCDNumber显⽰的数字值(double). |
digitCount | 显⽰⼏位数字. |
mode | 数字显⽰形式. |
segmentStyle | 设置显⽰⻛格. |
smallDecimalPoint | 设置⽐较⼩的⼩数点. |
3.2.2.1. 代码示例1:倒计时
- 在界面上创建一个QLCDNumber,初始值设置为5
- 修改widget.h和widget.cpp
#ifndefWIDGET_H
#defineWIDGET_H
#include<QWidget>
QT_BEGIN_NAMESPACE
namespaceUi{classWidget;}
QT_END_NAMESPACE
classWidget:publicQWidget
{
Q_OBJECT
public:
Widget(QWidget*parent=nullptr);
~Widget();
voidhandle();
privateslots:
private:
Ui::Widget*ui;
QTimer*timer;
};
#endif//WIDGET_H
#include"widget.h"
#include"ui_widget.h"
#include<QIcon>
#include<QRect>
#include<QPushButton>
#include<QDebug>
#include<QButtonGroup>
#include<QString>
#include<QResizeEvent>
#include<QSize>
#include<QTimer>
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->lcdNumber->display("10");
timer=newQTimer(this);
connect(timer,&QTimer::timeout,this,&Widget::handle);
timer->start(1000);
}
Widget::~Widget()
{
deleteui;
}
voidWidget::handle()
{
intvalue=ui->lcdNumber->intValue();
if(value<=0)
{
timer->stop();
return;
}
ui->lcdNumber->display(value-1);
}
QTimer表示定时器,同故宫start方法启动定时器,就会每隔一定周期,触发一次QTimer::timeout信号。使用connect把QTimer::timeout信号和Widget::handle连接起来,意味着每次触发QTimer::timeout都会执行Widget::updateTime
- 执行程序
针对上面的代码,如果直接在构造函数中,通过一个循环+sleep的方式是否可以实现这个效果?
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->lcdNumber->display("10");
timer=newQTimer(this);
//connect(timer,&QTimer::timeout,this,&Widget::handle);
//timer->start(1000);
intvalue=ui->lcdNumber->intValue();
while(true)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
if(value<=0)
{
break;
}
ui->lcdNumber->display(value-1);
}
}
这个代码是不行的,循环会使Widget的构造函数无法执行完毕,此时界面是不能正确构造和现实的。
直接在构造函数里不行,另起一个线程,在新线程中完成这个操作可以吗?
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->lcdNumber->display("10");
timer=newQTimer(this);
//connect(timer,&QTimer::timeout,this,&Widget::handle);
//timer->start(1000);
std::threadt([this](){
intvalue=this->ui->lcdNumber->intValue();
while(true)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
if(value<=0)
{
break;
}
this->ui->lcdNumber->display(value-1);
}
});
}
这个代码同样不行,Qt中规定,任何对于GUI上内容的操作,必须在主线程中完成,像Widget构造函数,以及connect连接的slot函数,都是在主线程中调用的,而我们自己创建的线程则不是,当我们自己的线程中尝试对界面元素进行修改的时候,Qt程序往往会直接崩溃。
这样的约定主要是因为GUI中的状态往往是牵⼀发动全⾝的,修改⼀个地⽅,就需要同步的对其他内容进⾏调整.⽐如调整了某个元素的尺⼨,就可能影响到内部的⽂字位置,或者其他元素的位置.这⾥⼀连串的修改,都是需要按照⼀定的顺序来完成的.由于多线程执⾏的顺序⽆法保障,因此Qt从根本上禁⽌了其他线程修改GUI状态,避免后续的⼀系列问题.
3.2.3. ProgressBar(进度条)
使用QProgressBar表示一个进度条
注意,不要把ProgessBar拼写成ProcessBar
属性 | 说明 |
minimum | 进度条最⼩值 |
maximum | 进度条最⼤值 |
value | 进度条当前值 |
alignment | ⽂本在进度条中的对⻬⽅式. •Qt::AlignLeft:左对⻬ |
textVisible | 进度条的数字是否可⻅. |
orientation | 进度条的⽅向是⽔平还是垂直 |
invertAppearance | 是否是朝反⽅向增⻓进度 |
textDirection | ⽂本的朝向. |
format | 展⽰的数字格式. |
3.2.3.1. 代码示例1:设置进度条按时间增长
- 在界面上创建进度条,objectName为progressBar
其中最小值设为0,最大值设为100
- 修改widget.h,创建QTimer和updateProgressBar函数
QT_BEGIN_NAMESPACE
namespaceUi{classWidget;}
QT_END_NAMESPACE
classWidget:publicQWidget
{
Q_OBJECT
public:
Widget(QWidget*parent=nullptr);
~Widget();
voidupdateProgressBa();
private:
Ui::Widget*ui;
QTimer*timer;
};
- 修改widget.cpp
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
timer=newQTimer(this);
connect(timer,&QTimer::timeout,this,&Widget::updateProgressBa);
timer->start(100);
}
Widget::~Widget()
{
deleteui;
}
voidWidget::updateProgressBa()
{
intvalue=ui->progressBar->value();
if(value>=100){
timer->stop();
}
else
{
ui->progressBar->setValue(value+1);
}
}
- 运行程序
在实际开发中,进度条的取值,往往是根据当前任务的实际进度来进⾏设置的.⽐如需要读取⼀个很⼤的⽂件,就可以获取⽂件的总的⼤⼩,和当前读取完毕的⼤⼩,来设置进度条的⽐例.由于上⾯我们介绍了Qt禁⽌在其他线程修改界⾯,因此进度条的更新往往也是需要搭配定时器来完成的.通过定时器周期触发信号,主线程调⽤对应的slot函数.再在slot函数中对当前的任务进度进⾏计算,并更新进度条的界⾯效果
3.2.4. CallendarWidget(日历)
QCalendarWidget表示一个"日历"
属性 | 说明 |
selectDate | 当前选中的⽇期 |
minimumDate | 最⼩⽇期 |
maximumDate | 最⼤⽇期 |
firstDayOfWeek | 每周的第⼀天(也就是⽇历的第⼀列)是周⼏. |
gridVisible | 是否显⽰表格的边框 |
selectionMode | 是否允许选择⽇期 |
navigationBarVisible | ⽇历上⽅标题是否显⽰ |
horizontalHeaderFormat | ⽇历上⽅标题显⽰的⽇期格式 |
verticalHeaderFormat | ⽇历第⼀列显⽰的内容格式 |
dateEditEnabled | 是否允许⽇期被编辑 |
重要信号
信号 | 说明 |
selectionChanged(const | 当选中的⽇期发⽣改变时发出 |
activated(constQDate&) | 当双击⼀个有效的⽇期或者按下回⻋键时发出,形参是⼀个QDate类型,保存 |
currentPageChanged(int, | 当年份⽉份改变时发出,形参表⽰改变后的新年份和⽉份 |
3.2.4.1. 代码示例1:获取选中的日期
- 在界面上创建一个QCalendarWidget和一个label
objectName为calendarWidget,label
- 给QCalendarWidget添加槽函数
voidWidget::on_calendarWidget_selectionChanged()
{
QDatedate=ui->calendarWidget->selectedDate();
ui->label->setText(date.toString());
}
- 执行程序
3.3. 输入类控件
3.3.1. LineEdit(单行输入)
QLineEdit用来表示单行输入框,可以输入一段文本,但是不能换行。
属性 | 说明 |
text | 输⼊框中的⽂本 |
inputMask | 输⼊内容格式约束 |
maxLength | 最⼤⻓度 |
frame | 是否添加边框 |
echoMode | 显⽰⽅式. |
cursorPosition | 光标所在位置 |
alignment | ⽂字对⻬⽅式,设置⽔平和垂直⽅向的对⻬. |
dragEnabled | 是否允许拖拽 |
readOnly | 是否是只读的(不允许修改) |
placeHolderText | 当输⼊框内容为空的时候,显⽰什么样的提⽰信息 |
clearButtonEnabled | 是否会⾃动显⽰出"清除按钮". |
重要信号
属性 | 说明 |
voidcursorPositionChanged(intold,intnew) | 当⿏标移动时发出此信号,old为先前的位置,new为新位置。 |
voideditingFinished() | 当按返回或者回⻋键时,或者⾏编辑失去焦点时,发出此信号。 |
voidreturnPressed() | 当返回或回⻋键按下时发出此信号.如果设置了验证器,必须要验证通过,才能触发. |
voidselectionChanged() | 当选中的⽂本改变时,发出此信号。 |
voidtextChanged(constQString&text) | 当QLineEdit中的⽂本改变时,发出此信号,text是新的⽂本。代码对⽂本的修改能够触发这个信号. |
voidtextEdited(constQString&text)) | 当QLineEdit中的⽂本改变时,发出此信号,text是新的⽂本。代码对⽂本的修改不能触发这个信号. |
3.3.1.1. 代码示例1:录入个人信息
- 在界⾯上创建三个输⼊框和两个单选按钮,⼀个普通按钮,三个输入框的objectName为lineEdit_name/password/phone,两个单选按钮objectName为radioButton_male,radioButton_female按钮的objectName为pushButton
2.修改widget.cpp
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->lineEdit_name->setPlaceholderText("Pleaseenterthename");
ui->lineEdit_name->setClearButtonEnabled(true);
ui->lineEdit_password->setEchoMode(QLineEdit::Password);
ui->lineEdit_password->setClearButtonEnabled(true);
ui->lineEdit_phone->setPlaceholderText("Pleaseenterthephonenumber");
ui->lineEdit_phone->setClearButtonEnabled(true);
ui->lineEdit_phone->setInputMask("000-0000-0000");
}
- 添加slot函数
voidWidget::on_pushButton_clicked()
{
QStringgender=ui->radioButton_male->isChecked()?"男":"女";
qDebug()<<"name:"<<ui->lineEdit_name->text();
qDebug()<<"pwd:"<<ui->lineEdit_password->text();
qDebug()<<"sex:"<<gender;
qDebug()<<"phone:"<<ui->lineEdit_phone->text();
}
- 执行
inputMask只能进⾏简单的输⼊格式校验.实际开发中,基于正则表达式的⽅式是更核⼼的⽅法.
3.3.1.2. 代码示例2:使用正则表达式验证输入框的数据
次数要求在输入框中输入一个合法的电话号发(1开头,11位全是数字),如果格式不正确,则确定按钮无法点击。
关于正则表达式
正则表达式是⼀种在计算机中常⽤的,使⽤特殊字符描述⼀个字符串的特征的机制.在进⾏字
符串匹配时⾮常有⽤.
正则表达式的语法还⽐较复杂,⼀般都是随⽤随查,不需要背下来.
\A:表示从字符串的开始处匹配
\Z:表示从字符串的结束处匹配,如果存在执行,只匹配到换行前的结束字符串
\b:匹配一个单词边界,也就是说指单词和空格间的位置。
\B:匹配非单词边界。
\d:匹配任意数字,等价于---[0-9]
\D:匹配任意非数字字符,等价于---[^\d]
\s:匹配任意空白字符,等价于---[\t\n\r\f]
\S:匹配任意非空白字符,等价于---[^\s]
\w:匹配任意字母数字及下划线,等价于---[a-zA-Z0-9]
\W:匹配任意非字母数字及下划线,等价于---[^\w]
\\:匹配原义的反斜杠\
---------------------------------------
[]:用于表示一组字符,如果^事第一个字符,则表示的是一个补集,比如[0-9]表示所有的数字,[^0-9]表示除了数字外的字符
.:用于匹配除换行符之外的所有字符
^:用于匹配字符串的开始.及行首
$:用于匹配字符串的末尾(末尾如果有换行符,就匹配换行符前面的那个字符),及行尾
*:用于将前面的模式匹配0次或多次(贪婪模式,及尽可能多的匹配)
+:用于将前面的模式匹配1次或多次(贪婪模式)
?:用于将前面的模式匹配0次或1次(贪婪模式)
*?,+?,??是上面三种特殊字符的非贪婪模式(尽可能少的匹配)
{m}:用于验证将前面的模式匹配m次
{m,}:用于验证将前面的模式匹配m次或者多次--->>=m次
{m,n}:用于将前面的模式匹配m次到n次(贪婪模式),即最小匹配m次,最大匹配n次
{m,n}?即上面{m,n}的非贪婪模式
\\:\是转义字符,在特殊字符前面加上\,特殊字符就失去了其所代表的含义,比如\+就仅仅代表加号本身
|:比如A|B用于匹配A或B
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
QRegExpregExp("^1\\d{10}$");//创建一个正则对象,
//^表示匹配字符串的开始位置
//1表示匹配数字1
//\d表示匹配任意数字
//{10}表示重复匹配十次前面的模式
//$表示匹配字符串的结束位置
ui->lineEdit->setValidator(newQRegExpValidator(regExp));
//设置一个验证器
ui->pushButton->setEnabled(false);
}
Widget::~Widget()
{
deleteui;
}
//on_lineEdit_textEdited的参数是当前输⼊框的内容.
voidWidget::on_lineEdit_textEdited(constQString&arg1)
{
QStringcontent=arg1;
intpos=0;
//通过lineEdit->validator()获取到内置的验证器.
//过validate⽅法验证⽂本是否符合要求.
//◦第⼀个参数填写的是要验证的字符串.由于参数要求是QString&⽽不是const
//QString&,需要把这个变量复制⼀下.
//◦第⼆个参数是⼀个int&,是输出型参数.当验证的字符串不匹配时,返回这个字符串的⻓度.(没有
//啥实质作⽤).
//返回值是⼀个枚举.QValidator::Acceptable表⽰验证通过,
//QValidator::Invalid表⽰验证不通过.
if(ui->lineEdit->validator()->validate(content,pos)==QValidator::Acceptable)
{
ui->pushButton->setEnabled(true);
}
else
{
ui->pushButton->setEnabled(false);
}
}
3.3.1.3. 代码示例3:切换显示密码
- 创建一个输入框和一个复选按钮
- 修改widget.cpp
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->lineEdit->setEchoMode(QLineEdit::Password);
}
Widget::~Widget()
{
deleteui;
}
voidWidget::on_checkBox_toggled(boolchecked)
{
if(checked){
ui->lineEdit->setEchoMode(QLineEdit::Normal);
}else{
ui->lineEdit->setEchoMode(QLineEdit::Password);
}
}
- 执行程序
3.3.2. TextEdit(多行输入)
QTextEdit表示多行输入框,也是一个富文本&markdown编辑器,并且能在内容超出编辑框范围时,自动提供滚动条。
属性 | 说明 |
markdown | 输⼊框内持有的内容.⽀持markdown格式.能够⾃动的对markdown⽂本进⾏渲染成html |
html | 输⼊框内持有的内容.可以⽀持⼤部分html标签.包括img和table等. |
placeHolderText | 输⼊框为空时提⽰的内容. |
readOnly | 是否是只读的 |
undoRedoEnable | 是否开启undo/redo功能. |
autoFormating | 开启⾃动格式化. |
tabstopWidth | 按下缩进占多少空间 |
overwriteMode | 是否开启覆盖写模式 |
acceptRichText | 是否接收富⽂本内容 |
verticalScrollBarPolicy | 垂直⽅向滚动条的出现策略 Qt::ScrollBarAlwaysOn:总是显⽰滚动条。 |
horizontalScrollBarPolicy | ⽔平⽅向滚动条的出现策略 |
核心信号
信号 | 说明 |
textChanged() | ⽂本内容改变时触发 |
selectionChanged() | 选中范围改变时触发 |
cursorPositionChanged() | 光标移动时触发 |
undoAvailable(bool) | 可以进⾏undo操作时触发 |
redoAvailable(bool) | 可以进⾏redo操作时触发 |
copyAvaiable(bool) | ⽂本被选中/取消选中时触发 |
3.3.2.1. 代码示例1:获取多行输入框的内容
- 创建一个多行输入框和一个label
2.给多行输入框添加slot函数,处理textChanged信号
通过toPlainText方法获取到内部的文本
类似的,QTextEdit还提供了toMarkdown和toHtml,根据需要我们调整不同的获取方式。
voidWidget::on_textEdit_textChanged()
{
constQString&text=ui->textEdit->toPlainText();
ui->label->setText(text);
}
- 执行代码,就可以看到输入框中内容发生变化的时候,label也会同步发生变化。
3.3.3. ComboBox(下拉框)
QComboBox表示下拉框
重要属性
属性 | 说明 |
currentText | 当前选中的⽂本 |
currentIndex | 当前选中的条⽬下标.从0开始计算.如果当前没有条⽬被选中,值为-1 |
editable | 是否允许修改 |
iconSize | 下拉框图标(⼩三⻆)的⼤⼩ |
maxCount | 最多允许有多少个条⽬ |
重要方法
⽅法 | 说明 |
addItem(constQString&) | 添加⼀个条⽬ |
currentIndex() | 获取当前条⽬的下标 |
currentText() | 获取当前条⽬的⽂本内容. |
重要信号
⽅法 | 说明 |
activated(int) | 当⽤⼾选择了⼀个选项时发出. |
currentIndexChanged(int) | 当前选项改变时发出. |
editTextChanged(constQString& | 当编辑框中的⽂本改变时发出 |
3.3.3.1. 代码示例1:使用下拉框模拟点餐
- 在界面上创建三个下拉框,和一个按钮
- 修改widget.cpp
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->comboBox_1->addItem("炒面");
ui->comboBox_1->addItem("炒米");
ui->comboBox_2->addItem("薯条");
ui->comboBox_2->addItem("可比克");
ui->comboBox_3->addItem("可乐");
ui->comboBox_3->addItem("雪碧");
}
Widget::~Widget()
{
deleteui;
}
voidWidget::on_pushButton_clicked()
{
qDebug()<<ui->comboBox_1->currentText();
qDebug()<<ui->comboBox_2->currentText();
qDebug()<<ui->comboBox_3->currentText();
}
- 执行程序
3.3.3.2. 代码示例2:从文件中加载下拉框的选项
- 在界面上创建一个下拉框
- 创建文件d:/config.txt,编写选项,每个选项占一行
- 修改widget.cpp
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
//读取文件内容,把文件中的每一行读取出来,作为comboBox的内容
std::ifstreamfile("D:/code_qt/test/untitled1/config.txt");
if(!file.is_open()){
qDebug()<<"filefail";
return;
}
//按行读取文本内容
std::stringline;
while(std::getline(file,line))
{
ui->comboBox->addItem(QString::fromStdString(line));
}
file.close();
}
- 执行程序,就可以看到效果了
3.3.4. SpinBox(微调框)
使⽤QSpinBox或者QDoubleSpinBox表⽰"微调框",它是带有按钮的输⼊框.可以⽤来输⼊整数/浮点数.通过点击按钮来修改数值⼤⼩.
由于SpinBox和QDoubleSpinBox⽤法基本相同,就只介绍SpinBox的使⽤了
常用属性
属性 | 说明 |
value | 存储的数值. |
singleStep | 每次调整的"步⻓".按下⼀次按钮数据变化多少. |
displayInteger | 数字的进制.例如displayInteger设为10,则是按照10进制表⽰.设为2则为2进制表⽰. |
minimum | 最⼩值 |
maximum | 最⼤值 |
suffix | 后缀 |
prefix | 前缀 |
wrapping | 是否允许换⾏ |
frame | 是否带边框 |
alignment | ⽂字对⻬⽅式. |
readOnly | 是否允许修改 |
buttonSymbol | 按钮上的图标. UpDownArrows上下箭头形式 |
accelerated(加速的) | 按下按钮时是否为快速调整模式 |
correctionMode
| 输⼊有误时如何修正. |
keyboardTrack
| 是否开启键盘跟踪. |
常用信号
信号 | 说明 |
textChanged(QString) | 微调框的⽂本发⽣改变时会触发.参数QString带有前缀和后缀. |
valueChanged(int) | 微调框的⽂本发⽣改变时会触发.参数int,表⽰当前的数值. |
3.3.4.1. 代码示例1:调正购物车中的份数
- 在界面中创建三个下拉框,三个微调框,一个按钮
- 修改widget.cpp
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->spinBox->setValue(1);
ui->spinBox->setRange(1,99);
ui->spinBox_2->setValue(1);
ui->spinBox_2->setRange(1,99);
ui->spinBox_3->setValue(1);
ui->spinBox_3->setRange(1,99);
}
Widget::~Widget()
{
deleteui;
}
voidWidget::on_pushButton_clicked()
{
qDebug()<<ui->comboBox_1->currentText()<<""<<ui->spinBox->value();
qDebug()<<ui->comboBox_2->currentText()<<""<<ui->spinBox_2->value();
qDebug()<<ui->comboBox_3->currentText()<<""<<ui->spinBox_3->value();
}
- 执行代码
3.3.5. DateEdit&TimeEdit&DateTimeEdit(日期&时间&时间日期的微调框)
使用QDateEdit作为日期的微调框,使用QTimeEdit作为时间的微调框,QDateTimeEdit作为时间日期的微调框
以QDateTimeEdit为例进行介绍
常用属性
属性 | 说明 |
dateTime | 时间⽇期的值.形如2000/1/10:00:00 |
date | 单纯⽇期的值.形如2001/1/1 |
time | 单纯时间的值.形如0:00:00 |
displayFormat | 时间⽇期格式.形如yyyy/M/dH:mm |
minimumDateTime | 最⼩时间⽇期 |
maximumDateTime | 最⼤时间⽇期 |
timeSpec | •Qt::LocalTime:显⽰本地时间。 |
常用信号
信号 | 说明 |
dateChanged(QDate) | ⽇期改变时触发. |
timeChanged(QTime) | 时间改变时触发. |
dateTimeChanged(QDateTi | 时间⽇期任意⼀个改变时触发. |
3.3.5.1. 代码示例1:实现日期计算器
- 在界面上创建两个QDateTimeEdit和一个按钮,一个label,objectName为dateTimeEdit_old/new
- 修改widget.cpp
使⽤daysTo函数可以计算两个⽇期的天数.
使⽤secsTo函数可以计算两个时间的秒数.
通过(秒数/3600)换算成⼩时数,再余上24得到零⼏个⼩时.
使⽤QString::number把整数转成QString进⾏拼接.
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
deleteui;
}
voidWidget::on_pushButton_clicked()
{
//获取日期
QDateTimetimeOld=ui->dateTimeEdit_old->dateTime();
QDateTimetimeNew=ui->dateTimeEdit_new->dateTime();
qDebug()<<timeOld<<timeNew;
//计算天数
intdays=timeOld.daysTo(timeNew);
qDebug()<<days;
//计算秒
intseconds=timeOld.secsTo(timeNew);
//转换成小时
inthours=(seconds/3600)%24;
//把计算结果放到label中
ui->label->setText(QString("时间过了")+QString::number(days)+"天零"+QString::number(hours)+QString("小时"));
}
- 执行程序
3.3.6. Dial(旋钮)
使用QDial表示一个旋钮
常用属性
属性 | 说明 |
value | 持有的数值. |
minimum | 最⼩值 |
maximum | 最⼤值 |
singleStep | 按下⽅向键的时候改变的步⻓. |
pageStep | 按下pageUp/pageDown的时候改变的步⻓. |
sliderPosition | 界⾯上旋钮显⽰的初始位置 |
tracking | 外观是否会跟踪数值变化. |
wrapping | 是否允许循环调整. |
notchesVisible | 是否显⽰刻度线 |
notchTarget | 刻度线之间的相对位置. |
常用信号
属性 | 说明 |
valueChanged(int) | 数值改变时触发 |
rangeChanged(int,int) | 范围变化时触发 |
3.3.6.1. 代码示例1:调整窗口透明度
- 在界面上创建一个旋钮和一个label
- 修改eidget.cpp
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
deleteui;
}
voidWidget::on_dial_valueChanged(intvalue)
{
qDebug()<<value;
this->setWindowOpacity((double)value/100);
ui->label->setText("当前不透明度:"+QString::number(value/100));
}
- 运行程序
3.3.7. Slider(滑动条)
使用QSlider表示一个滑动条
🏝QSlider和QDial都是继承⾃QAbstractSlider,因此⽤法上基本相同.
常用属性
属性 | 说明 |
value | 持有的数值. |
minimum | 最⼩值 |
maximum | 最⼤值 |
singleStep | 按下⽅向键的时候改变的步⻓. |
pageStep | 按下pageUp/pageDown的时候改变的步⻓. |
sliderPosition | 滑动条显⽰的初始位置 |
tracking | 外观是否会跟踪数值变化. |
orientation | 滑动条的⽅向是⽔平还是垂直 |
invertedAppearance | 是否要翻转滑动条的⽅向 |
tickPosition | 刻度的位置. |
tickInterval | 刻度的密集程度. |
常用信号
属性 | 说明 |
valueChanged(int) | 数值改变时触发 |
rangeChanged(int,int) | 范围变化时触发 |
3.3.7.1. 代码示例1:
- 在界面上创建两个滑动条,分别是水平和垂直滑动条objectNmae为horizeontalSlider和verticalSlider
- 编写代码
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->horizontalSlider->setMinimum(100);
ui->horizontalSlider->setMaximum(2000);
ui->horizontalSlider->setValue(800);
ui->horizontalSlider->setSingleStep(50);
ui->verticalSlider->setMinimum(100);
ui->verticalSlider->setMaximum(1500);
ui->verticalSlider->setValue(600);
ui->verticalSlider->setSingleStep(50);
}
Widget::~Widget()
{
deleteui;
}
voidWidget::on_horizontalSlider_valueChanged(intvalue)
{
constQRect&rect=this->geometry();
this->setGeometry(rect.x(),rect.y(),value,rect.height());
}
voidWidget::on_verticalSlider_valueChanged(intvalue)
{
constQRect&rect=this->geometry();
this->setGeometry(rect.x(),rect.y(),rect.width(),value);
}
- 执行程序,可以通过调整滑动条改变窗口大小
3.4. 多元素控件
Qt中提供的多元素控件有
- QListWidget
- QListView
- QTableWidget
- QTableView
- QTreeWidget
- QTreeView
xxWidget和xxView之间的区别
以QTableWidget和QTableView为例.
QTableView是基于MVC设计的控件.QTableView⾃⾝不持有数据.使⽤QTableView的时候需要⽤⼾创建⼀个Model对象(⽐如QStandardModel),并且把Model和
QTableView关联起来.后续修改Model中的数据就会影响QTableView的显⽰;修改
QTableView的显⽰也会影响到Model中的数据(双向绑定).
QTableWidget则是QTableView的⼦类,对Model进⾏了封装.不需要⽤⼾⼿动创建
Model对象,直接就可以往QTableWidget中添加数据了.
3.4.1. ListWidget(纵向的列表)
使用QListWidget能够显示一个纵向的列表,每个选项都可以被选中
常用属性
属性 | 说明 |
currentRow | 当前被选中的是第⼏⾏ |
count | ⼀共有多少⾏ |
sortingEnabled | 是否允许排序 |
isWrapping | 是否允许换⾏ |
itemAlignment | 元素的对⻬⽅式 |
selectRectVisible | 被选中的元素矩形是否可⻅ |
spacing | 元素之间的间隔 |
常用方法
⽅法 | 说明 |
addItem(constQString&label) | 列表中添加元素. |
currentItem() | 返回QListWidgetItem*表⽰当前选中的元素 |
setCurrentItem(QListWidgetItem*item) | 设置选中哪个元素 |
setCurrentRow(introw) | 设置选中第⼏⾏的元素 |
insertItem(constQString&label,int | 在指定的位置插⼊元素 |
item(introw) | 返回QListWidgetItem*表⽰第row⾏的元素 |
takeItem(introw) | 删除指定⾏的元素,返回QListWidgetItem*表⽰是哪个元素被删除了 |
常用信号
⽅法 | 说明 |
currentItemChanged(QListWidgetItem*current,QListWidgetItem*old) | 选中不同元素时会触发.参数是当前选中的元素和之前选中的元素. |
currentRowChanged(int) | 选中不同元素时会触发.参数是当前选中元素的⾏数. |
itemClicked(QListWidgetItem*item) | 点击某个元素时触发 |
itemDoubleClicked(QListWidgetItem* | 双击某个元素时触发 |
itemEntered(QListWidgetItem*item) | ⿏标进⼊元素时触发 |
在上述介绍中,设计到一个关键的类,QListWidgetItem,这个类表示QListWidget中的一个元素
常用方法如下,本质上就是一个"文本+图标"构成的。
⽅法 | 说明 |
setFont | 设置字体 |
setIcon | 设置图标 |
setHidden | 设置隐藏 |
setSizeHint | 设置尺⼨ |
setSelected | 设置是否选中 |
setText | 设置⽂本 |
setTextAlignment | 设置⽂本对⻬⽅式. |
3.4.1.1. 代码示例1:使用ListWidget
- 在界面上创建一个ListView,右键变形为ListWidget,在创建一个lineEdit和两个按钮,
ListWidget是ListView的子类,功能比ListView更丰富
- 编写widget.cpp
Widget::Widget(QWidget*parent)
:QWidget(parent)
,ui(newUi::Widget)
{
ui->setupUi(this);
ui->listWidget->addItem("C/C++");
ui->listWidget->addItem("Python");
ui->listWidget->addItem("php");
}
Widget::~Widget()
{
deleteui;
}
voidWidget::on_pushButton_add_clicked()
{
//1.先获取到输入框中的内容
constQString&text=ui->lineEdit->text();
//2.添加到listwidget中
ui->listWidget->addItem(text);
}
voidWidget::on_pushButton_del_clicked()
{
//1.先获取到被选中的元素是哪个
introw=ui->listWidget->currentRow();
if(row<0){
return;
}
ui->listWidget->takeItem(row);
}
- 执行程序
3.4.2. TableWidget(表格控件)
使用QTableWidget表示一个表格控件,一个表格中包含若干行,每一行又包含若干列,表格中的每个单元格,是一个QTableWidgetItem对象
常用方法
⽅法 | 说明 |
item(introw,intcolumn) | 根据⾏数列数获取指定的QTableWidgetItem* |
setItem(introw,intc | 根据⾏数列数设置表格中的元素 |
currentItem() | 返回被选中的元素QTableWidgetItem* |
currentRow() | 返回被选中元素是第⼏⾏ |
currentColumn() | 返回被选中元素是第⼏列 |
row(QTableWidgetItem*) | 获取指定item是第⼏⾏ |
column(QTableWidgetItem*) | 获取指定item是第⼏列 |
rowCount() | 获取⾏数 |
columnCount() | 获取列数 |
insertRow(introw) | 在第row⾏处插⼊新⾏ |
insertColumn(intcolumn) | 在第column列插⼊新列 |
removeRow(introw) | 删除第row⾏ |
removeColumn(intcolumn) | 删除第column列 |
setHorizontalHeaderItem(int | 设置指定列的表头 |
setVerticalHeaderItem(introw, | 设置指定⾏的表头 |
常用信号
信号 | 说明 |
cellClicked(introw,intcolumn) | 点击单元格时触发 |
cellDoubleClicked(introw,int | 双击单元格时触发 |
cellEntered(introw,intcolumn) | ⿏标进⼊单元格时触发 |
currentCellChanged(introw,int | 选中不同单元格时触发 |
QTableWidgetItem常用方法
⽅法 | 说明 |
row() | 获取当前是第⼏⾏ |
column() | 获取当前是第⼏列 |
setText(constQString&) | 设置⽂本 |
setTextAlignment(int) | 设置⽂本对⻬ |
setIcon(constQIcon&) | 设置图标 |
setSelected(bool) | 设置被选中 |
setSizeHints(constQSize&) | 设置尺⼨ |
setFont(constQFont&) | 设置字体 |
3.4.2.1. 代码示例1:使用QTableWidget
- 在界面上创建QTableWidget和三个按钮,一个输入框
- 编写Widget,cpp函数
#include "widget.h"
#include "ui_widget.h"
#include <QIcon>
#include <QRect>
#include <QPushButton>
#include <QDebug>
#include <QButtonGroup>
#include <QString>
#include <QResizeEvent>
#include <QSize>
#include <thread>
#include <QRegExp>
#include <QRegExpValidator>
#include <fstream>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建3行
for (int i = 0; i < 3; i++)
{
ui->tableWidget->insertRow(i);
}
// 创建3列
for (int i = 0; i < 3; i++)
{
ui->tableWidget->insertColumn(i);
}
// 给3列设定列明
ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("sno"));
ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem("name"));
ui->tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem("age"));
// 设置初始数据
ui->tableWidget->setItem(0, 0, new QTableWidgetItem("1001"));
ui->tableWidget->setItem(0, 1, new QTableWidgetItem("张三"));
ui->tableWidget->setItem(0, 2, new QTableWidgetItem("15"));
ui->tableWidget->setItem(1, 0, new QTableWidgetItem("1002"));
ui->tableWidget->setItem(1, 1, new QTableWidgetItem("李四"));
ui->tableWidget->setItem(1, 2, new QTableWidgetItem("16"));
ui->tableWidget->setItem(2, 0, new QTableWidgetItem("1003"));
ui->tableWidget->setItem(2, 1, new QTableWidgetItem("王五"));
ui->tableWidget->setItem(2, 2, new QTableWidgetItem("17"));
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_add_row_clicked()
{
// 获取到行数
int rowCount = ui->tableWidget->rowCount();
// 插入新行
ui->tableWidget->insertRow(rowCount);
}
void Widget::on_pushButton_add_col_clicked()
{
int curRow = ui->tableWidget->columnCount();
ui->tableWidget->insertColumn(curRow);
}
void Widget::on_pushButton_del_row_clicked()
{
int curRow = ui->tableWidget->currentRow();
// 删除对应行
ui->tableWidget->removeRow(curRow);
}
void Widget::on_pushButton_del_col_clicked()
{
int curRow = ui->tableWidget->currentColumn();
ui->tableWidget->removeColumn(curRow);
}
- 执行代码就可以操作表格了
3.4.3. TreeWidget(树形控件)
使⽤ QTreeWidget 表⽰⼀个树形控件.⾥⾯的每个元素,都是⼀个 QTreeWidgetItem ,每个
QTreeWidgetItem 可以包含多个⽂本和图标,每个⽂本/图标为⼀个列.可以给QTreeWidget 设置顶层节点(顶层节点可以有多个),然后再给顶层节点添加⼦节点,从⽽构成树形结构.
方法 | 说明 |
clear | 清空所有子节点 |
addTopLevelItem(QTreeWidgetItem*item) | 新增顶层节点 |
topLevelItem(intindex) | 获取指定下标的顶层节点. |
topLevelItemCount() | 获取顶层节点个数 |
indexOfTopLevelItem(QTreeWidgetItem* | 查询指定节点是顶层节点中的下标 |
takeTopLevelItem(intindex) | 删除指定的顶层节点.返回QTreeWidgetItem*表⽰被删除 |
currentItem() | 获取到当前选中的节点,返回QTreeWidgetItem* |
setCurrentItem(QTreeWidgetItem*item) | 选中指定节点 |
setExpanded(bool) | 展开/关闭节点 |
setHeaderLabel(constQString&text) | 设置TreeWidget的header名称. |
常用信号
信号 | 说明 |
currentItemChanged(QTreeWidgetItem* | 切换选中元素时触发 |
itemClicked(QTreeWidgetItem*item,intcol) | 点击元素时触发 |
itemDoubleClicked(QTreeWidgetItem*item, | 双击元素时触发 |
itemEntered(QTreeWidgetItem*item,intcol) | ⿏标进⼊时触发 |
itemExpanded(QTreeWidgetItem*item) | 元素被展开时触发 |
itemCollapsend(QTreeWidgetItem*item) | 元素被折叠时触发 |
QTreeWidgetItem 核⼼属性
属性 | 说明 |
text | 持有的文本 |
textAlignment | 文本对齐方式 |
icon | 持有的图表 |
font | ⽂本字体 |
hidden | 是否隐藏 |
disabled | 是否禁⽤ |
expand | 是否展开 |
sizeHint | 尺⼨⼤⼩ |
selected | 是否选中 |
QTreeWidgetItem 核⼼⽅法
⽅法 | 说明 |
addChild(QTreeWidgetItem*child) | 新增⼦节点 |
childCount() | ⼦节点的个数 |
child(intindex) | 获取指定下标的⼦节点.返回QTreeWidgetItem* |
takeChild(intindex) | 删除对应下标的⼦节点 |
removeChild(QTreeWidgetItem* | 删除对应的⼦节点 |
parent() | 获取该元素的⽗节点 |
3.4.3.1. 代码示例1:QTreeWidget
- 在界面上创建一个TreeWidget,在创建一个lineEdit和两个按钮
- 编写代码,构造初始数据
#include "widget.h"
#include "ui_widget.h"
#include <QIcon>
#include <QRect>
#include <QPushButton>
#include <QDebug>
#include <QButtonGroup>
#include <QString>
#include <QResizeEvent>
#include <QSize>
#include <thread>
#include <QRegExp>
#include <QRegExpValidator>
#include <fstream>
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);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
const QString& text = ui->lineEdit->text();
if (text.isEmpty())
{
return;
}
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, text);
ui->treeWidget->addTopLevelItem(item);
}
void Widget::on_pushButton_2_clicked()
{
const QString& text = ui->lineEdit->text();
if (text.isEmpty())
{
return;
}
QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();
if (currentItem == nullptr) {
return;
}
QTreeWidgetItem* newItem = new QTreeWidgetItem();
newItem->setText(0, text);
currentItem->addChild(newItem);
currentItem->setExpanded(true);
}
void Widget::on_pushButton_3_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);
}
}
- 执行代码
3.5. 容器类控件
3.5.1. GroupBox(分组框)
使⽤ QGroupBox 实现⼀个带有标题的分组框.可以把其他的控件放到⾥⾯作为⼀组.这样看起来能更好看⼀点.
常用属性
属性 | 说明 |
title | 分组框的标题 |
alignment | 分组框内部内容的对⻬⽅式 |
flat | 是否是"扁平"模式 |
checkable | 是否可选择. |
checked | 描述分组框的选择状态(前提是checkable为true) |
分组框只是⼀个⽤来"美化界⾯"这样的组件,并不涉及到⽤⼾交互和业务逻辑.属于"锦上添
花".
3.5.1.1. 代码示例1:给麦当劳案例加上分组框
- 在界面上创建三个分组框,并且在分组框内部创建下拉框和微调框
- 在ui中设置一些属性
- 运行代码,这就是分组框的作用。
3.5.2. TabWidget(带有标签页的控件)
使⽤ QTabWidget 实现⼀个带有标签⻚的控件,可以往⾥⾯添加⼀些widget.进⼀步的就可以通过标签⻚来切换.
常用属性
属性 | 说明 |
tabPosition | 标签⻚所在的位置. |
currentIndex | 当前选中了第⼏个标签⻚(从0开始计算) |
currentTabText | 当前选中的标签⻚的⽂本 |
currentTabName | 当前选中的标签⻚的名字 |
currentTabIcon | 当前选中的标签⻚的图标 |
currentTabToolTip | 当前选中的标签⻚的提⽰信息 |
tabsCloseable | 标签⻚是否可以关闭 |
movable | 标签⻚是否可以移动 |
常用信号
属性 | 说明 |
currentChanged(int) | 在标签⻚发⽣切换时触发,参数为被点击的选项卡编号. |
tabBarClicked(int) | 在点击选项卡的标签条的时候触发.参数为被点击的选项卡编号. |
tabBarDoubleClicked(int) | 在双击选项卡的标签条的时候触发.参数为被点击的选项卡编号. |
tabCloseRequest(int) | 在标签⻚关闭时触发.参数为被关闭的选项卡编号. |
3.5.2.1. 代码示例1:使用标签页管理多组控件
- 在界面上创建一个QTabWideget,和两个按钮,objectName为pushButton_add/del
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QLabel* label = new QLabel(ui->tab);
label->setText("标签页1");
// label->resize(100, 50);
QLabel* label2 = new QLabel(ui->tab_2);
label2->setText("标签页2");
}
- 编写slot函数
使⽤ count() 获取到标签⻚的个数.
使⽤ addTab 新增标签⻚.
使⽤ removeTab 删除标签⻚.
使⽤ currentIndex 获取到当前标签⻚的下标.
使⽤ setCurrentIndex 切换当前标签⻚.
#include "widget.h"
#include "ui_widget.h"
#include <QIcon>
#include <QRect>
#include <QPushButton>
#include <QDebug>
#include <QButtonGroup>
#include <QString>
#include <QResizeEvent>
#include <QSize>
#include <thread>
#include <QRegExp>
#include <QRegExpValidator>
#include <QLabel>
#include <fstream>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QLabel* label = new QLabel(ui->tab);
label->setText("标签页1");
// label->resize(100, 50);
QLabel* label2 = new QLabel(ui->tab_2);
label2->setText("标签页2");
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_add_clicked()
{
int cnt = ui->tabWidget->count();
QWidget* w = new QWidget();
ui->tabWidget->addTab(w, QString("Tab ") + QString::number(cnt + 1));
QLabel* label = new QLabel(w);
label->setText(QString("标签页") + QString::number(cnt + 1));
ui->tabWidget->setCurrentIndex(cnt);
}
void Widget::on_pushButton_del_clicked()
{
int index = ui->tabWidget->currentIndex();
ui->tabWidget->removeTab(index);
}
- 执行程序
3.6. 布局管理器
之前使⽤Qt在界⾯上创建的控件,都是通过"绝对定位"的⽅式来设定的.也就是每个控件所在的位置,都需要计算坐标,最终通过setGeometry 或者move ⽅式摆放过去.这种设定⽅式其实并不⽅便.尤其是界⾯如果内容⽐较多,不好计算.⽽且⼀个窗⼝⼤⼩往往是可以调整的,按照绝对定位的⽅式,也⽆法⾃适应窗⼝⼤⼩.因此Qt引⼊"布局管理器"(Layout)机制,来解决上述问题.
当然,布局管理器并⾮Qt独有.其他的GUI开发框架,像Android,前端等也有类似的机制.
3.6.1. QVBoxLayout(垂直布局)
使⽤ QVBoxLayout 表⽰垂直的布局管理器.V是 vertical 的缩写.
常用属性
属性 | 说明 |
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上⽅边距 |
layoutBottomMargin | 下⽅边距 |
layoutSpacing | 相邻元素之间的间距 |
Layout只是⽤于界⾯布局,并没有提供信号
3.6.1.1. 代码示例1:使用QVBoxLayout管理多个控件
- 编写代码,创建布局管理器和三个按钮,并且把按钮添加到布局管理器中。
• 使⽤ addWidget 把控件添加到布局管理器中.
• 使⽤ setLayout 设置该布局管理器到widget中.
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
QPushButton* btn3 = new QPushButton("按钮3");
// 创建布局管理器,并把按钮添加进去,如果创建的时候指定父元素为this,则后面不需要setLayout方法了
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(btn1);
layout->addWidget(btn2);
layout->addWidget(btn3);
// 把布局管理器设置到widget中
this->setLayout(layout);
}
3.6.2. QHBoxLayout(水平布局)
使⽤ QHBoxLayout 表⽰垂直的布局管理器.H是 horizontal 的缩写.
核⼼属性(和 QVBoxLayout 属性是⼀致的)
属性 | 说明 |
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上⽅边距 |
layoutBottomMargin | 下⽅边距 |
layoutSpacing | 相邻元素之间的间距 |
3.6.2.1. 代码示例1:使用QHBoxLayout管理控件
- 使用代码创建三个按钮,并将按钮加入到布局管理器当中
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
QPushButton* btn3 = new QPushButton("按钮3");
// 创建布局管理器,并把按钮添加进去,如果创建的时候指定父元素为this,则后面不需要setLayout方法了
QHBoxLayout* layout = new QHBoxLayout();
layout->addWidget(btn1);
layout->addWidget(btn2);
layout->addWidget(btn3);
this->setLayout(layout);
}
- 执行代码
3.6.2.2. 代码示例2:嵌套布局
- 创建三个按钮,将其中两个按钮水平布局,再将整体竖直布局
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
QPushButton* btn3 = new QPushButton("按钮3");
QPushButton* btn4 = new QPushButton("按钮4");
// 创建布局管理器,并把按钮添加进去,如果创建的时候指定父元素为this,则后面不需要setLayout方法了
QHBoxLayout* layout = new QHBoxLayout();
layout->addWidget(btn1);
layout->addWidget(btn2);
QVBoxLayout* q = new QVBoxLayout();
q->addWidget(btn3);
q->addWidget(btn4);
q->addLayout(layout);
this->setLayout(q);
}
3.6.3. QGridLayout(网格布局)
Qt中还提供了 QGridLayout ⽤来实现⽹格布局的效果.可以达到M*N的这种⽹格的效果.
核⼼属性
整体和 QVBoxLayout 以及 QHBoxLayout 相似.但是设置spacing的时候是按照垂直⽔平两个⽅向来设置的.
属性 | 说明 |
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上⽅边距 |
layoutBottomMargin | 下⽅边距 |
layoutHorizontalSpacing | 相邻元素之间⽔平⽅向的间距 |
layoutVerticalSpacing | 相邻元素之间垂直⽅向的间距 |
layoutRowStretch | ⾏⽅向的拉伸系数 |
layoutColumnStretch | 列⽅向的拉伸系数 |
3.6.3.1. 代码示例1:使用QGridLayout管理元素
- 代码中创建QGridLayout和四个按钮
使用addWidget添加控件到布局管理器中,但是添加的同时会指定两个坐标,表示放在第几行,第几列
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
QPushButton* btn3 = new QPushButton("按钮3");
QPushButton* btn4 = new QPushButton("按钮4");
// 创建网格布局管理器,并且添加元素
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到窗口中
this->setLayout(layout);
}
3.6.4. 表单布局
除了上述的布局管理器之外,Qt还提供了 QFormLayout ,属于是 QGridLayout 的特殊情况,专⻔⽤于实现两列表单的布局.
这种表单布局多⽤于让⽤⼾填写信息的场景.左侧列为提⽰,右侧列为输⼊框.
3.6.4.1. 代码示例1:使用QFormLayout创建表单
- 创建QFormaLayout,以及三个label和三个lineEdit,使用addRow方法添加一行,每行包含两个控件,第一个控件固定式QLabel/文本,第二个控件则可以是任意控件,如果把第一个参数填写为NULL,则什么都不显示
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QFormLayout* layout = new QFormLayout();
this->setLayout(layout);
QLabel* l1 = new QLabel("name");
QLabel* l2 = new QLabel("age");
QLabel* l3 = new QLabel("tel");
QLineEdit* e1 = new QLineEdit();
QLineEdit* e2 = new QLineEdit();
QLineEdit* e3 = new QLineEdit();
// 创建一个提交按钮
QPushButton* btn = new QPushButton("提交");
// 把上述元素移动到layout当中
layout->addRow(l1, e1);
layout->addRow(l2, e2);
layout->addRow(l3, e3);
layout->addRow(nullptr, btn);
}
3.6.5. Spacer(添加一段空白)
使⽤布局管理器的时候,可能需要在控件之间,添加⼀段空⽩.就可以使⽤ QSpacerItem 来表⽰.
核⼼属性
属性 | 说明 |
width | 宽度 |
height | ⾼度 |
hData | ⽔平⽅向的sizePolicy |
vData | 垂直⽅向的sizePolicy |
上述属性在构造函数设置即可.
3.6.5.1. 代码示例1:创建一组左右排列的按钮
- 在界面上创建一个QVBoxLayout,并添加两个按钮
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");
layout->addWidget(btn1);
layout->addWidget(btn2);
}
运行代码后发现,两个按钮离得很近
- 在两个按钮中间添加一个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");
QSpacerItem* spacer = new QSpacerItem(200, 20);
layout->addWidget(btn1);
layout->addSpacerItem(spacer);
layout->addWidget(btn2);
}