一、项目(框架建立)
(一)ui布局及QSS
1、嵌入式设备界面
2、windows软件界面
3、pad界面
4、QSS使用
4.1 将QSS文件添加到项目中
4.2 在项目的资源中添加该文件
4.3 在构造函数中通过路径读取QSS文件
QString qss;
QFile qssFile(":/res/qss/white.qss");
qssFile.open(QFile::ReadOnly);
if(qssFile.isOpen())
{
qss=QLatin1String(qssFile.readAll());
this->setStyleSheet(qss);
qssFile.close();
}
参考
资源
收集的QSS皮肤风格文件https://download.csdn.net/download/weixin_58619060/88862911
QSS组件皮肤生成器https://download.csdn.net/download/weixin_58619060/88862945
Qt的项目框架参考https://download.csdn.net/download/weixin_58619060/88862929
QSS-Skin-Builder皮肤生成器及其相关框架https://download.csdn.net/download/weixin_58619060/88862959
(二)创建资源文件并显示图片
第一步:创建文件夹,把图片保存到自己的工程目录下
图片名称为image1.png,我这里放在了image文件夹中
第二步:添加qrc资源文件
选中项目右键,添加新文件
选择Qt Resource File,点击Choose
然后给资源文件qrc取个名字,我这里取的名字是ret
第三步:给资源文件添加具体图片
右键ret.qrc,Open in Editor
然后会显示image.qrc这个窗口,点击下面添加前缀按钮
注:可以添加前缀也可以不用添加前缀,添加前缀是为了更好区分资源。前缀名如果不知道起什么,就用“/”即可,然后点击add files
然后,就可以点击添加文件。此时会弹出选择框让我们选择。
注:路径太长有2种方式更改路径名
1、直接更改真实文件名
缺点:1、要修改大量图片真实文件名,操作复杂。2、图片会直接跳出创建的资源文件夹外面(此处是image文件夹)
可以看到,资源文件中image文件已经没有,而且改名为1.png后直接出现在image文件夹外面,此时image文件夹完全没有作用
2、为文件取别名
优点:1、 如果要更改大量同种类型文件路径,不需要关心文件真实文件名。2、图片不会跳出资源文件夹外面
第四步:使用图片并显示
我们选择设计模式,在窗口界面中,选中要显示图片的label (效果如下图蓝色虚框),右键--->修改样式表
点击添加资源,选择border-image或者image(为什么选择?详细如下)
关于background-image、border-image、image的说明
1、background-image
setStyleSheet("background-image:url(:/image/image1.png);");
特点:不会自动适应图片,如果图片过小,将会图片裁剪填充其他区域;过大,截取一部分区域填充(平铺)
效果如下:
2、border-image
setStyleSheet("border-image:url(:/image/image1.png);");
特点:会自适应部件区域大小,可以有拉伸效果但是会让边框不可见,如下图蓝色边框消失
效果如下:
3、image
setStyleSheet("image:url(:/image/image1.png);");
特点: 会自适应部件区域大小,不可以有拉伸效果,哪条边最小长宽自适应哪条边
效果如下:
(三)主页ToolBar(工具栏)的创建和设置
1、项目创建QMainWidget
2、为ToolBar添加控件
首先创建一个主窗口ui,默认带有一个TooBar(工具栏),在ui界面拖动四个ToolButton按钮,并为四个按钮添加图标。
3、添加代码,让这四个按钮出现在工具栏上面
//ui->toolBar 是我们的工具栏
ui->toolBar->addWidget(ui->toolButton);
ui->toolBar->addWidget(ui->toolButton_2);
ui->toolBar->addWidget(ui->toolButton_3);
ui->toolBar->addWidget(ui->toolButton_4);
效果如下:
4、常用属性
movable 属性
该属性属性用来确认toolBar是否可以移动,该属性默认true
ui界面设置:
代码可通过isMovable()和setMovable(),访问和设置该属性
allowedAreas 属性
该属性指定工具栏允许移动的范围,默认值是AllToolBarAreas,其余五个值分别是窗口左边,右边,菜单下,底部状态栏之上,以及NoToolBarArea(没有设定工具栏区域,意味着你可以把它任意地方)
ui界面设置:
代码可通过allowedAreas() 和setAllowedAreas,访问和设置该变量
iconSize 属性
该属性设置图标栏,大小
ui界面设置:
toolButtonStyle 属性
该属性指定按钮显示模式,默认为ToolButtonIconOnly(仅显示图标)
其他四个值分别为:
ToolButtonTextOnly(只显示文字)
ToolButtonTextBesideIcon(文字在图标旁)
ToolButtonTextUnderIcon(文字在图标下)
ToolButtonFollowStyle(根据QStyle::StyleHint格式显示,我们没有设置StyleHint,所以和默认一样)
ui界面设置:
代码可通过toolButtonStyle()和setToolButtonStyle(),访问和设置该属性
此属性定义所有作为QAction添加的工具按钮的样式。请注意,如果使用addWidget()方法添加QToolButton,它将不会获得此按钮样式
要使工具按钮的样式遵循系统设置,请将此属性设置为Qt :: ToolButtonFollowStyle
floatble 属性
该属性保存是否可以将工具栏作为独立窗口进行拖放,默认是true
当设置为false,虽然鼠标可以拖动工具栏,但无法独立出来
ui界面设置:
代码可通过isFloatable()和setFloatable(),访问和设置该属性
arrowType属性
该属性是按钮是否显示箭头从而代替普通图标,默认值是NoArrow,如果将其设置为DownArrow,则如下图所示,此外还有其他朝向三个方向箭头的值供选择
注意:当设置该属性,按钮上已存在的图标,文字等都会被覆盖
ui界面可设置:
代码可通过arrowType()和setArrowType(),访问和设置该属性
autoRaise属性
该属性决定按钮是否有边框,默认值是False,与正常按钮一样,当设置为true时,如下图:
当鼠标划过时,会自动弹起
代码可通过autoRaise()和setAutoRaise(),访问和设置该属性
popupMode属性
该属性可设置弹出菜单的方式,默认是DelayedPopup(值为0,按下按钮一定时间后,显示菜单)
首先需要有下拉菜单才能看到效果
QMenu *menu=new QMenu(this);
menu->addAction(QIcon(":/image/image2.png"),"工程0",this,SLOT(doSlot()));
menu->addAction(QIcon(":/image/image2.png"),"工程1",this,SLOT(doSlot()));
menu->addAction(QIcon(":/image/image2.png"),"工程2",this,SLOT(doSlot()));
menu->addAction(QIcon(":/image/image2.png"),"工程3",this,SLOT(doSlot()));
menu->addAction(QIcon(":/image/image2.png"),"工程4",this,SLOT(doSlot()));
menu->addAction(QIcon(":/image/image2.png"),"工程5",this,SLOT(doSlot()));
menu->addAction(QIcon(":/image/image2.png"),"工程6",this,SLOT(doSlot()));
ui->toolButton->setMenu(menu);
此时会出现“箭头”下标并且有下拉项,如下图:
(1)InstantPopup:鼠标放在ToolButton上,延时几秒后弹出下拉项
(2)MenuButtonPopup:会在右侧出现一个下拉“箭头”,只有点击“箭头”才能弹出下拉项,点击ToolButton则不会弹出下拉项
(3)InstantPopup:点击ToolButton则立即弹出下拉项
ui界面可设置:
代码可通过popupMode()和setPopupMode(),访问和设置该属性
(四)同一窗口下的多个页面切换
1、使用QStackedWidget
1.1 创建StackedWdiget
注意:刚拖拽的StackedWdiget默认是有两个page页的,所以currentIndex(0)和currentIndex(1)已经存在,当我们addWidget后通过currentIndex(2)才能访问刚刚加入的widget窗口。也可以将默认的2个page删除重新从currentIndex(0)开始
1.2 创建新的Widget并加入StackWidget中,点击切换
#include "widget.h"
#include "ui_widget.h"
#include "ui_form.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
page1 = new Form(this);
page1->ui->groupBox->setTitle("page1");
page2 = new Form(this);
page2->ui->groupBox->setTitle("page2");
//将两个widget添加至stackedWidget
ui->stackedWidget->addWidget(page1);
ui->stackedWidget->addWidget(page2);
//设置stackedWidget当前展示页面
ui->stackedWidget->setCurrentIndex(0);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
ui->stackedWidget->setCurrentIndex(0);
}
void Widget::on_pushButton_2_clicked()
{
ui->stackedWidget->setCurrentIndex(1);
}
效果如下:
注意:想要页面自适应窗口,必须将StackWidget和Page页面都做成自适应窗口,如下所示:
2、使用QStackedLayout
2.1 创建一个container容器,这里是拖拽的Widget容器
2.2 将自定义类加入容器中
#include "widget.h"
#include "ui_widget.h"
#include "ui_form.h"
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
page1 = new Form(this);
page1->ui->groupBox->setTitle("page1");
page2 = new Form(this);
page2->ui->groupBox->setTitle("page2");
//创建QStackedLayout,并将Page加入QVBoxLayout
layout = new QStackedLayout(ui->widget);//指定父类(自己拖拽的Widget组件),Widget组件里放一个QStackedLayout,也可以写成如下所示
// ui->widget->setLayout(layout);
//将page1、page2加入到layout中
layout->addWidget(page1);
layout->addWidget(page2);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
layout->setCurrentIndex(0);
}
void Widget::on_pushButton_2_clicked()
{
layout->setCurrentIndex(1);
}
(五) 带滑动条的窗口
1、选择QT Creator左侧类栏中的Scroll Area,拖放到UI上,调整大小覆盖UI
注意:当拖拽QScrollArea时,它里面还存在一个QWdiget,我们的内容就放在QWidget里面
2、修改scrollArea其中三个属性,具体如下图:
verticalScrollBarPolicy设置为ScrollBarAlwaysOn:开启垂直滚动条
horizontalScrollBarPolicy设置为ScrollBarAlwaysOn:开启水平滚动条
widgetResizable设置为空:不会自动调整部件QWidget的大小,这样设置使QWdiget长宽都能超过QScrollArea的长宽,这样可以利用额外空间
3、修改scrollAreaWidgetContents(QWidget)的大小
注意:这个属性要比scrollArea要大,不然无法水平或者垂直滑动
效果如下:
(六)动态添加或删除控件
1、Widget添加或删除
1.1 创建一个容器(QWidget)和一个自定义组件,如下:
1.2 在widget里面放入一个QVBoxLayout布局,点击添加则将组件放入布局中,删除则从布局中移除并删除组件
#include "widget.h"
#include "ui_widget.h"
#include "ui_form.h"
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
num = 1;
layout = new QVBoxLayout(ui->widget);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
Form *page = new Form;
page->ui->label->setText(QString("label:%1").arg(num));
page->ui->label_2->setText(QString("label:%1").arg(num));
layout->addWidget(page);
num++;
}
void Widget::on_pushButton_2_clicked()
{
if(num > 1){
QWidget *widget = layout->itemAt(num - 2)->widget();
layout->removeWidget(widget);
delete widget;
num--;
}
}
效果如下:
2、QScrollArea里添加或删除
2.1 创建一个容器(QScrollArea)和一个自定义组件,1.1已经创建,此处不再创建
2.2 根据拖拽的QScrollArea设置相关参数
-
scrollArea:
widgetResizable
设置为true
,这样当添加的组件超出可视区域时,QScrollArea
会自动调整大小并显示滚动条。horizontalScrollBarPolicy
和verticalScrollBarPolicy
设置为Qt::ScrollBarAsNeeded
,表示根据需要显示滚动条。- 将
sizeAdjustPolicy
设置为AdjustToContents
,这样QWidget
的大小会根据添加的内容自动调整。
-
scrollAreaWidgetContents:
- 将
sizePolicy
的Vertical Policy
设置为Fixed
,这样可以固定高度,不会因为内容过多而改变大小。
- 将
2.3 在scrollAreaWidgetContents里面放入一个QVBoxLayout布局,点击添加则将组件放入布局中,删除则从布局中移除并删除组件
#include "widget.h"
#include "ui_widget.h"
#include "ui_form.h"
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
num = 1;
layout = new QVBoxLayout(ui->scrollAreaWidgetContents);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
Form *page = new Form(this);
page->ui->label->setText(QString("label:%1").arg(num));
page->ui->label_2->setText(QString("label:%1").arg(num));
layout->addWidget(page);
num++;
}
void Widget::on_pushButton_2_clicked()
{
if(num > 1){
QWidget *widget = layout->itemAt(num - 2)->widget();
layout->removeWidget(widget);
delete widget;
num--;
}
}
效果如下:
(七)字体跟随控件自适应
问题:当屏幕的缩放比例变化时,qt 控件上的字体出现显示不全现象
解决办法:
1、在当前的项目中添加文件夹etc,etc文件夹下添加一个文件,文件命名为qt.conf,然后添加资源文件
文件内容:
[Platforms]
WindowsArguments = dpiawareness=0
2、将etc文件夹下的qt.conf 添加到资源文件夹下。(右键->添加现有文件)
3、重新构建项目
(八)自定义标题栏
在项目中,我们一般会使用自定义标题栏来设计。功能一般有放大、缩小、关闭、拖拽、拉伸、阴影等,如下:
代码实现:
header:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMouseEvent>
#include <QNetworkAccessManager>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
void mousePressEvent(QMouseEvent*event);
void mouseMoveEvent(QMouseEvent*event);
void mouseReleaseEvent(QMouseEvent*event);
void mouseDoubleClickEvent(QMouseEvent*event);
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
private:
void windowMin();
void windowMax();
void windowClose();
private:
Ui::MainWindow *ui;
bool isPressed;
bool isMaxWin;
QPoint curPos;
};
#endif // MAINWINDOW_H
cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#ifdef Q_OS_WIN
#include <qt_windows.h>
#include <Windowsx.h>
#endif
#include <QDebug>
#include <QDesktopWidget>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//隐藏系统标题栏,并允许放大缩小
setWindowFlags(Qt::FramelessWindowHint | Qt::Window | Qt::WindowMinimizeButtonHint);
connect(ui->btnMin,&QPushButton::clicked,this,&MainWindow::windowMin);
connect(ui->btnMax,&QPushButton::clicked,this,&MainWindow::windowMax);
connect(ui->btnClose,&QPushButton::clicked,this,&MainWindow::windowClose);
isPressed=false;
isMaxWin=false;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow:: mouseDoubleClickEvent(QMouseEvent*event)
{
Q_UNUSED(event);
if(ui->titleWidget->underMouse())
{
this->showNormal();
isMaxWin=false;
}
}
void MainWindow::mousePressEvent(QMouseEvent*event)
{
if(event->button()==Qt::LeftButton
&& ui->titleWidget->underMouse()) //如果鼠标左键处于标题栏并且按下
{
isPressed=true;
curPos=event->pos(); //记录当前的点击坐标
}
}
void MainWindow::mouseMoveEvent(QMouseEvent*event)
{
if(isPressed) //如果鼠标左键按下
{
this->move(event->pos()-curPos+this->pos()); //窗口移动
if(isMaxWin)
{
windowMax();
// this->showMaximized();
}
}
}
//鼠标释放
void MainWindow::mouseReleaseEvent(QMouseEvent*event)
{
isPressed=false;
}
//关闭窗口
void MainWindow::windowClose()
{
qApp->exit();
}
//窗口最小化
void MainWindow::windowMin()
{
this->showMinimized();
}
//窗口最大化
void MainWindow::windowMax()
{
isMaxWin=!isMaxWin;
if(isMaxWin) //根据是否最大化窗口,改变对应的图标
{
ui->btnMax->setIcon(QIcon(":/icons/normal.png"));
this->showMaximized();
this->showFullScreen(); //fixed
}
else
{
ui->btnMax->setIcon(QIcon(":/icons/maxsize.png"));
this->showNormal();
}
}
//消息处理
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
int m_nBorder = 5; //设置一个边界宽度用于判断是否处于边界
Q_UNUSED(eventType)
MSG *param = static_cast<MSG *>(message);
switch (param->message)
{
case WM_NCHITTEST:
{
int nX = GET_X_LPARAM(param->lParam) - this->geometry().x();
int nY = GET_Y_LPARAM(param->lParam) - this->geometry().y();
*result = HTCAPTION;
//判断鼠标位置是否位于窗口边界
if ((nX > 0) && (nX < m_nBorder))
*result = HTLEFT;
if ((nX > this->width() - m_nBorder) && (nX < this->width()))
*result = HTRIGHT;
if ((nY > 0) && (nY < m_nBorder))
*result = HTTOP;
if ((nY > this->height() - m_nBorder) && (nY < this->height()))
*result = HTBOTTOM;
if ((nX > 0) && (nX < m_nBorder) && (nY > 0)
&& (nY < m_nBorder))
*result = HTTOPLEFT;
if ((nX > this->width() - m_nBorder) && (nX < this->width())
&& (nY > 0) && (nY < m_nBorder))
*result = HTTOPRIGHT;
if ((nX > 0) && (nX < m_nBorder)
&& (nY > this->height() - m_nBorder) && (nY < this->height()))
*result = HTBOTTOMLEFT;
if ((nX > this->width() - m_nBorder) && (nX < this->width())
&& (nY > this->height() - m_nBorder) && (nY < this->height()))
*result = HTBOTTOMRIGHT;
if (*result == HTCAPTION)
{
return false;
}
return true;
}
}
return QMainWindow::nativeEvent(eventType, message, result);
}
(九)窗口无放大、缩小标志(只有关闭标志)
this->window()->setWindowFlags(this->window()->windowFlags() & ~Qt::WindowMaximizeButtonHint & ~Qt::WindowMinimizeButtonHint);
效果图:
(十)窗口相关设置
//隐藏系统标题栏,并允许放大缩小
setWindowFlags(Qt::FramelessWindowHint | Qt::Window | Qt::WindowMinimizeButtonHint);
//全屏显示
showFullScreen();
//是否影响用户与其他窗口的交互方式。用户必须与当前模态窗口进行交互,才能返回到应用程序中的其他窗口
setWindowModality(Qt::ApplicationModal);
注意:
- Qt::NonModal: 窗口是非模态的。用户可以同时与应用程序中的任何窗口进行交互,不会受到限制。
- Qt::WindowModal: 窗口是窗口模态的。用户只能与当前窗口所在的父窗口进行交互,而无法与其他兄弟窗口交互。适用于需要用户在处理当前窗口的内容之前不能操作其他窗口的场景。
- Qt::ApplicationModal: 窗口是应用程序模态的。用户必须与当前模态窗口进行交互,才能返回到应用程序中的其他窗口。这种模态性通常用于阻止用户与应用程序的其他部分进行交互,直到当前窗口处理完毕。适用于对用户必须立即处理的情况。
// 设置新窗口为始终保持在前面窗口的上方
[窗口对象]->setParent(this);
[窗口对象]->setWindowFlags([窗口对象]->windowFlags() | Qt::Dialog);
//主窗口关闭后,所有窗口是否都关闭
setAttribute(Qt::WA_QuitOnClose, false);
注意:
窗口的Qt::WA_QuitOnClose属性默认为true,意思是该窗口参与主程序的退出流程。如果一个子窗口没有指定父类,且在关闭主窗口时子窗口也是打开的,那么关闭主窗口时这个子窗口并不会关闭,也不会退出主程序。设置为false则表示该窗口不参与退出主程序流程,关闭主窗体就退出主程序。
// 设置窗口为透明背景
setAttribute(Qt::WA_TranslucentBackground);
没有设置之前:
背景相当于布局的主窗口,如下:
(十一) QProgressBar设置为整数且不按比例
// %v 表示当前值,%m 表示最大值
ui->progressBar->setFormat(QStringLiteral("%v/%m"));
设置为%p
结果是:
设置为%v
结果是:
二、布局
(一)基本布局管理器
基本布局管理器QBoxLayout类可以使子部件在水平方向或者垂直方向排成一列,它将所有的空间分成一行盒子,然后将每个部件放入一个盒子中。
(二)栅格布局管理器(QGridLayout)
栅格布局管理器QGridLayout类使部件在网格中进行布局,它将所有的空间分隔成一些行和列,行和列的交叉处形成了单元格,然后将部件放入一个确定的单元格中。
(三)组件的大小策略(QSizePolicy)
sizeHint:
sizeHint
是部件的推荐大小,是部件希望拥有的大小建议值。例如,在一个垂直布局中,添加了一个按钮部件,按钮的sizeHint
返回的大小为 100 x 50 像素,则按钮在布局中会尽量保持这个大小。但如果布局的限制条件使得按钮无法达到这个大小,布局管理器可能会调整按钮的大小以适应布局。
常量 | 描述 |
---|---|
Fixed | 只能使用sizeHint的值,无法伸缩 |
Minimum | 控件的sizeHint为控件的最小尺寸。控件不能小于sizeHint,但是可以放大 |
Maximum | 控件的sizeHint为控件的最大尺寸。控件不能大于sizeHint,但是可以缩小到它的最小的允许尺寸 |
Preferred | 控件的sizeHint就是它的大小,但是可以放大和缩小 |
Expanding | 控件可以自行放大和缩小 |
Ignored | sizeHint的值被忽略,倾向于被拉伸 |
(四)弹簧条属性
在进行窗口布局的时候为了让界面看起来更加美观,需要调整控件的位置,比如:靠左,靠右,居中,又或者我们需要调节两个控件之间的距离,以上这些需求使用弹簧都是可以实现的。
关于弹簧的 sizeType 属性,有很多选项,一般常用的只有两个:
- Fixed: 得到一个固定大小的弹簧
- Expanding: 得到一个可伸缩的弹簧,默认弹簧撑到最大
(五)分裂器(QSplitter)和Frame
1、QSplitter
分裂器QSplitter类提供了一个分裂器部件。和QBoxLayout类似,可以完成布局管理器的功能,但是包含在它里面的部件,默认是可以随着分裂器的大小变化而变化的。比如一个按钮放在布局管理器中,它的垂直方向默认是不会被拉伸的,但是放到分裂器中就可以被拉伸。还有一点不同就是,布局管理器继承自QObject类,而分裂器却是继承自QFrame类,QFrame类又继承自QWidget类,也就是说,分裂器拥有QWidget类的特性,它是可见的,而且可以像QFrame一样设置边框。
属性中的opaqueResize默认情况下(打勾),使用鼠标拖动分割子窗口间的边界时,子窗口会动态的改变其大小。然而,如果希望在松开鼠标时才改变其大小,可以设置下面的参数,取消其勾选状态即可,效果如下(打勾):
2、Frame
可以和container嵌套使用,如下:
(六)关于Minimum或Maxmum与Expanding的区别
1、使用Minimum或Maxmum时
效果如下:
可以看到,中间按钮没有变化
2、使用Expanding
效果如下:
可以看到,中间按钮变化了(自适应屏幕)
3、结论
按道理来说,这两个例子长宽都能进行放大,加入弹簧后按道理中间按钮应该不变,那为什么Expanding会变化(自适应屏幕)?
-
Minimum
策略表示部件希望保持其最小尺寸,即在布局中尽可能地小,但不会小于其最小尺寸。如果一个部件的sizePolicy
在水平或垂直方向上被设置为Minimum
,那么该部件将会尽量保持其最小尺寸(需要扩大的时候才扩大)。 -
Expanding
策略表示部件希望在布局中尽可能地扩展,以填充可用的空间。如果一个部件的sizePolicy
在水平或垂直方向上被设置为Expanding
,那么该部件将会尽可能地占据额外的可用空间。 -
当部件的
sizePolicy
被设置为Minimum
时,部件会按照其sizeHint
的建议大小和最小尺寸进行布局调整。如果部件没有足够的空间来显示其最小尺寸,那么部件可能会被截断或者溢出。当部件的
sizePolicy
被设置为Expanding
时,部件会尽可能地占据额外的可用空间,以填充布局中的空白区域。这意味着部件会自适应地扩展以填充布局的剩余空间。关于弹簧(Stretch)的作用,当在布局中添加了弹簧时,弹簧会占据布局中的额外空间,并根据部件的
sizePolicy
来分配剩余空间。如果使用了Minimum
策略,部件将会保持其最小尺寸,不会填充额外空间;而如果使用了Expanding
策略,部件将会自适应地填充额外空间。因此,当使用了弹簧并且部件的
sizePolicy
被设置为Expanding
时,部件会自适应地填充额外空间,以实现自动调整大小的效果。
在 Qt 布局开发中,常用的 sizePolicy
主要有以下几种设置:
-
Fixed(固定大小):
- 部件将保持其固定大小,不会根据布局的大小变化而改变。
-
Minimum(最小大小):
- 部件会尽可能地保持其最小大小,但可以根据布局的需要进行扩展。
-
Maximum(最大大小):
- 部件会尽可能地保持其最大大小,但可以根据布局的需要进行缩小。
-
Preferred(首选大小):
- 部件会尽可能地保持其首选大小,但也会根据布局的需要进行调整。
-
Expanding(扩展大小):
- 部件会尽可能地扩展到填充可用空间的大小,填充布局中的剩余空间。
4、加强示例
图4.1:
图4.2:
为什么将标题栏水平改成“min”后界面变了?
minimum含义:使用时尽可能小,需要它时才扩大
expanding含义:使用时尽可能扩大
当标题栏为expanding时,会向两端膨胀,当都改成min时,界面水平会保持一个平衡状态。举个例子:将两个弹簧粘在一起,用手拉住弹簧两端,此时弹簧会保持一个平衡状态
5、加强示例
(七)删除布局中所有控件函数
void clearLayout(QLayout *layout)
{
if (!layout) return;
QLayoutItem *item;
while ((item = layout->takeAt(0))) {
QWidget *widget = item->widget();
if (widget) {
delete widget; // 删除控件
}
QLayout *subLayout = item->layout();
if (subLayout) {
clearLayout(subLayout); // 递归清除子布局
delete subLayout; // 删除子布局
}
delete item; // 删除项
}
}
三、常用知识(常用类及相关代码)
(一)QByteArray
概述
QByteArray 是 Qt 框架中用于存储字节数组的类,它提供了一系列操作字节数组的函数。
-
字符和字符串:
当你向 QByteArray 中插入字符或者字符串时,它内部实际存储的是这些字符或字符串的 UTF-8 编码。UTF-8 是一种可变长度的字符编码方式,可以将 Unicode 字符以一至四个字节的形式编码为字节序列。 -
整数:
对于较大的整数(如 int 类型,通常是 32 位),Qt 会将其按照小端(little-endian)顺序转换为四个字节,并依次存储在 QByteArray 中。这意味着最低有效字节(最右边的字节)会被存储在最前面的位置。
当你将一个整数(比如 int、quint8、qint16 等)插入 QByteArray 中时,Qt 会根据整数的类型和大小,将其转换为一个或多个字节。例如,一个quint8
类型的整数(即无符号 8 位整数),会被转换为一个字节,范围是 0 到 255。 -
16进制数:
16进制数通常是以字符串的形式插入到 QByteArray 中。这些字符串可以包含数字 '0' 到 '9' 和字母 'a' 到 'f'(或大写字母 'A' 到 'F'),以表示各种字节的16进制值。
常见函数
QByteArray::append
将一个字节数组添加到另一个字节数组末尾。
QByteArray array;
array.append('a');
array.append("aa");
array.append(15);
array.append(16);
qDebug() << array;//结果是"aaa\x0F\x10"
QByteArray::insert
在指定位置插入一个字节数组(从下标0开始,不能插入字符‘0’)。
QByteArray array;
array.insert(0,1);
array.insert(1,2);
array.insert(2,3);
array.insert(3,4);
qDebug() << array;//结果是"\x01\x02\x03\x04"
QByteArray::toHex
将字节数组转换为十六进制字符串。
QByteArray array;
array.insert(0,0xa);
array.insert(1,0xb);
array.insert(2,0xc);
array.insert(3,0xd);
QString str = array.toHex();
qDebug() << str;//结果是"0a0b0c0d"
QByteArray::fromHex
将十六进制字符串转换为字节数组。
QString hexString("12345678");
//hexString.toUtf8()虽然是QByteArray类型,但相当于就是字符串,只不过是utf-8编码的字符串
QByteArray byteArray = QByteArray::fromHex(hexString.toUtf8());
qDebug() << byteArray;//结果是"\x12\x34\x56\x78"
(二)QString
常见函数
QString::toInt
将字符串数字转换为对应进制的整形数字。
int toInt(bool *ok = Q_NULLPTR, int base = 10) const
long toLong(bool *ok = Q_NULLPTR, int base = 10) const
short toShort(bool *ok = Q_NULLPTR, int base = 10) const
uint toUint(bool *ok = Q_NULLPTR, int base = 10) const
ulong toUlong(bool *ok = Q_NULLPTR, int base = 10) const
bool ok;
QString str("0f");
int num = str.toInt(&ok,16);
qDebug() << num;//结果是整数15
QString::number
整数转换为不同进制的QString字符串。
static QString number(int, int base=10);
static QString number(uint, int base=10);
static QString number(long, int base=10);
static QString number(ulong, int base=10);
static QString number(qlonglong, int base=10);
static QString number(qulonglong, int base=10);
static QString number(double, char f='g', int prec=6);第一个参数:待转换数字
第二个参数(整型):转换进制
第二个参数(浮点数):浮点数格式
第三个参数(浮点数):保留小数位数
//===========示例一===========
QString str = QString::number(10,16);
qDebug() << str;//结果是'a'
//===========示例二===========
QString str = QString::number(32, 'f', 2);
qDebug() << str;//结果str == "32.00"
QString::split
将一个字符串根据指定的分隔符分割成多个子字符串,并将这些子字符串存储在一个 QStringList
中返回。
QString str = "apple,orange,banana";
QStringList parts = str.split(",");
qDebug() << parts;
QString::mid
用于提取字符串中的指定起始位置的子串。
QString str = "Hello,World";
QString subStr1 = str.mid(6); // 从位置6开始提取到末尾
QString subStr2 = str.mid(0, 5); // 从位置0开始提取5个字符
qDebug() << subStr1;//结果是"World"
qDebug() << subStr2;//结果是"Hello"
QString::rightJustified
用于在字符串的左侧填充字符,使得字符串达到指定的宽度。
QString str("af");
str = str.rightJustified(8,'0');
qDebug() << str;//结果是"000000af"
QString::arg
格式化字符串,可以指定字符串长度和填充字符。
QString QString::arg(uint a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char( ' ' )) const
fieldWidth :格式化后的字符串宽度;
base :指定将整数a转换为字符串时使用的基数(默认是十进制),还可以是二进制2 ,十六进制 16;
fillChar :待填充字符
int data = 15;//data=0xf一样的
QString str = QString("%1").arg(data, 8, 2, QChar('0'));
qDebug() << str;//结果是"00001111"
去掉QString空格
去掉QString首尾空格:QString trimmed() const
去掉QString内所有空格:QString simplified() const