目录
1. 前言
2. QWidget核心属性
2.1. enabled(控件是否可用)
2.2. geometry(尺寸)
2.2.1. windowframe的影响
2.3. windowTitle(窗口标题)
2.4. windowIcon(窗口图标)
2.5. 使用qrc文件资源管理
2.6. windowOpacity(半透明效果)
2.7. cursor(设置鼠标光标)
2.8. font(字体)
2.9. toolTip(鼠标悬停说明)
2.10. focusPolicy(设置控件获取焦点的策略)
2.11. styleSheet(通过CSS设置widget的样式)
3. 常用控件
3.1. 按钮类控件
3.1.1. PushButton(普通按钮)
3.1.1.1. 示例1:带有图标的按钮
3.1.1.2. 示例2:带有快捷键的按钮
3.1.2. RadioButton(单选按钮)
3.1.2.1. 代码示例1:选择技术
3.1.2.2. 代码示例2:click,press,release,toggled的区别
3.1.2.3. 代码示例3:单选框分组
3.1.3. CheckBox(复选按钮)
3.1.3.1. 代码示例:获取复选按钮的取值
3.2. 显示类控件
3.2.1. Label(显示文本和图片)
3.2.1.1. 代码示例1:显示不同格式的文本
3.2.1.2. 代码示例2:显示图片
3.2.1.3. 代码示例3:文本对齐,自动换行,缩进,边距
3.2.1.4. 代码示例4:设置伙伴
3.2.2. LCDNumber(专门用来显示数字)
3.2.2.1. 代码示例1:倒计时
3.2.3. ProgressBar(进度条)
3.2.3.1. 代码示例1:设置进度条按时间增长
3.2.4. CallendarWidget(日历)
3.2.4.1. 代码示例1:获取选中的日期
3.3. 输入类控件
3.3.1. LineEdit(单行输入)
3.3.1.1. 代码示例1:录入个人信息
3.3.1.2. 代码示例2:使用正则表达式验证输入框的数据
3.3.1.3. 代码示例3:切换显示密码
3.3.2. TextEdit(多行输入)
3.3.2.1. 代码示例1:获取多行输入框的内容
3.3.3. ComboBox(下拉框)
3.3.3.1. 代码示例1:使用下拉框模拟点餐
3.3.3.2. 代码示例2:从文件中加载下拉框的选项
3.3.4. SpinBox(微调框)
3.3.4.1. 代码示例1:调正购物车中的份数
3.3.5. DateEdit&TimeEdit&DateTimeEdit(日期&时间&时间日期的微调框)
3.3.5.1. 代码示例1:实现日期计算器
3.3.6. Dial(旋钮)
3.3.6.1. 代码示例1:调整窗口透明度
3.3.7. Slider(滑动条)
3.3.7.1. 代码示例1:
3.4. 多元素控件
3.4.1. ListWidget(纵向的列表)
3.4.1.1. 代码示例1:使用ListWidget
3.4.2. TableWidget(表格控件)
3.4.2.1. 代码示例1:使用QTableWidget
3.4.3. TreeWidget(树形控件)
3.4.3.1. 代码示例1:QTreeWidget
3.5. 容器类控件
3.5.1. GroupBox(分组框)
3.5.1.1. 代码示例1:给麦当劳案例加上分组框
3.5.2. TabWidget(带有标签页的控件)
3.5.2.1. 代码示例1:使用标签页管理多组控件
3.6. 布局管理器
3.6.1. QVBoxLayout(垂直布局)
3.6.1.1. 代码示例1:使用QVBoxLayout管理多个控件
3.6.2. QHBoxLayout(水平布局)
3.6.2.1. 代码示例1:使用QHBoxLayout管理控件
3.6.2.2. 代码示例2:嵌套布局
3.6.3. QGridLayout(网格布局)
3.6.3.1. 代码示例1:使用QGridLayout管理元素
3.6.4. 表单布局
3.6.4.1. 代码示例1:使用QFormLayout创建表单
3.6.5. Spacer(添加一段空白)
3.6.5.1. 代码示例1:创建一组左右排列的按钮
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);
}