Qt系统学习第二章 Qt窗口系统 (资源文件图片添加, QDialog, QMessageBox, 布局, 控件, Qt样式表)
资源文件:
QMainWindow :
在菜单栏中,文件下面的下拉框中,不能直接输入中文,可以先随便写个英文名,然后在对应所属的状态栏中找到
,将text右侧的“save”改为“保存”
,即可
;
这里的“保存”和“打开”可以通过拖动鼠标来改变顺序;
将菜单栏中的按钮放入工具栏:在ui界面中的Action Editor里面选择要放入工具栏的action;然后鼠标点住别放,往工具栏中拖,若出现红色竖杠,就表示此处可以拖入,此时松开鼠标即可完成拖入。
运行起来的程序,工具栏是可以自由拖动停靠的,要想不可拖动停靠,可以在ui界面的右侧的对象中找mainToolBar,在下面的属性中找QToolBqr,将movable后面的框框里,把对号去掉,就无法移动了
,将allowedAreas
控件中的Dock Widget是浮动窗口;属性中的floating是浮动与否,windowTitle是浮动窗口的小标题
QMenu (菜单栏)----- 只有一个
toolbar (工具栏)----- 可以有很多个
dockwidget (浮动窗口)--可以有很多个
statusBar(下状态栏)----- 只有一个
程序中,初始化一个变量的方式有两种: 在.h的private下面定义一个int number; 可以在.cpp中这样初始化.
qt中,通过代码添加资源文件(.qrc)如图:
方式一:
这种比较麻烦;
方式二:
可以通过右键左侧文件夹 -> 添加新文件-> 文件和类"Qt" -> Qt Resource File -> choose -> 指定名称(英文) -> .qrc 添加到文件 -> 完成 -> 项目所属的.pro中出现 Resource += ***.qrc
此时左侧文件树中出现,双击resource.qsc是无法打开的, 此时想要编辑,应该鼠标右键单击resource.qrc -> Open With -> 资源编辑器;
打开后, 点击 "添加" 按钮 -> 添加前缀 -> 修改前缀(最简单的前缀就是一个/) -> 点击 "添加" 按钮 -> 添加文件 -> 将所用到的图标资源文件放入一个Image文件夹中, 再复制粘贴到工程所在目录中 -> 鼠标左键拉选所用图片 -> 选好后,点击右下方 "打开" 即可完成添加资源文件;
此时的左侧文件树可以看到资源文件, 同时, 可以在添加前缀那块在添加个文件前缀, 放别的资源文件进来, 方便后期项目过大时区分资源文件;
同时,将.cpp文件中的资源文件地址更换
ui->actionsave_as->setIcon(QIcon(":/caidanlan/Image/1.jpg"));
此时的程序编译时, 运行速度会变慢, 是因为编译器在编译的时候, 将我们所添加的资源文件, 转换成了二进制文件, 存入了程序中, 以后打包软件的时候,也将图片一起打包了就.
方式三:
添加完资源文件前缀及文件后,在.ui界面的Action Editor中,选择所要添加资源文件的action; 然后查看右侧的属性窗口里找icon
点开下拉框后,找到Normal Off/On,然后点击其中一个
右侧的 "..." ,弹出资源文件窗口
;此时选择一个图标, 选择, 点击OK即可;此时
出现图标,若想改变图标大小, 可在.ui界面的右侧的对象窗口里 找到并选中mainToolBar
, 然后在右下角的属性窗口中,找到QToolBar -> iconSize, 在这里可以改变图标的宽高;iconText是图标文本内容; 当图标插入后,Qt默认不显示文字,可将鼠标悬浮于图标之上,1s后,可显示出提示文字;提示文字可在iconText同级下面一行的toolTip后面设置;
QDialog :
模态对话框: 无法对对话框后的文件进行编辑或处理;且有系统提示音;
非模态对话框: 可以对对话框后的文件进行编辑或处理;
PS: 使用QT类主要记 这个类, 都有哪些信号, 和槽函数. Qt中,用宏的时候,记不住宏的名字,也可以用宏编码
dlg->setAttribute(Qt::WA_DeleteOnClose); //关闭窗口后,自窗口自动被析构.此处的是QObject派生的子类,父类窗口不关闭(析构),子类也不会被析构
//dlg->setAttribute(55); //在文档助手里,上述宏对应的编号就是55
QMessageBox:
提示对话框:
本节代码如下:
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QFileDialog> #include <QDebug> #include <QPushButton> #include <QLabel> #include <QDialog> //对话框类 #include <QMessageBox> //提示对话框 #include <QColorDialog> //颜色对话框 #include <QFontDialog> //字体对话框 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), number(10) //初始化 方式1 { ui->setupUi(this); //number = 10; //初始化 方式2 //ui->menuEdit->addAction(); connect(ui->actionopen, &QAction::triggered, this, [=]() { // //创建一个对话框 // QDialog dlg(this); //如果没有(this),意思是dlg是个独立的顶层窗口,加了(this)意思是,指定了父类是MainWindow(看本代码第九行) // //显示模态对话框 .exec() // dlg.exec(); //阻塞 关闭模态对话框后,程序才可以继续执行 // QString name = QFileDialog::getOpenFileName(this, "打开文件", "D:\\", "Image (*.jpg *.png )"); // qDebug() << name.toUtf8().data(); //qDebug不能直接打印Qstring类型的,需要先转成QByteArray{toUtf8()},,再转成char *QByteArray {data()} //QMessageBox::about(this,"about","*******"); //QMessageBox::critical(this,"error","系统文件错误!!!",QMessageBox::Ok | QMessageBox::Cancel); // | 是为了区分,在Open的时候可能会加参数,比如只读/只写, QMessageBox::Ok 和QMessageBox::Cancel 对应的都是数值, 转换为二进制后, 只占其中一位.将这两个按位异或的方式放入整数里,占很多的位,通过对应位来判断所设属性 //if(QMessageBox::Ok == QMessageBox::critical(this,"error","系统文件错误!!!",QMessageBox::Ok | QMessageBox::Cancel)) //是个红色大错号 //if(QMessageBox::Ok == QMessageBox::information(this,"error","系统文件错误!!!",QMessageBox::Ok | QMessageBox::Cancel)) //是个蓝色感叹号 //if(QMessageBox::Ok == QMessageBox::warning(this,"error","系统文件错误!!!",QMessageBox::Ok | QMessageBox::Cancel)) //是个黄色感叹号, 并设置Cancel为默认按钮 // if(QMessageBox::Ok == QMessageBox::question(this,"error","系统文件错误!!!",QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel)) //是个蓝色问号 // { // QDialog dlg(this); // dlg.exec(); // } // QColor color = QColorDialog::getColor(); // qDebug() << color.red() << color.green() << color.blue(); //颜色对话框 bool ok; QFont font = QFontDialog::getFont(&ok, QFont("华文彩云"), this, "我的字体设置"); if(ok) { qDebug() << font.family() << font.italic() << font.pointSize() << font.bold(); //字体类型 << 倾斜与否 << 高度 << 加粗与否 } }); connect(ui->actionsave, &QAction::triggered, this, [=]() { //创建一个对话框 QDialog *dlg = new QDialog(this); //此时运行,非模态对话框一闪而过,此处new是为了不析构这个dlg,使对话框一直存在,也可以while(1){} //但是弊端是,这个程序运行起来后,有可能会反复点击一万次"save"按钮, 来创建这个窗口, 这就意味着被new了一万次, 但是一次都没被析构. 解决办法是 将QDialog *dlg定义为成员变量.这样就可以在外部释放,这样比较麻烦. //也可以设置对话框属性 dlg->setAttribute(Qt::WA_DeleteOnClose); //关闭窗口后,自窗口自动被析构.此处的是QObject派生的子类,父类窗口不关闭(析构),子类也不会被析构 //dlg->setAttribute(55); //在文档助手里,上述宏对应的编号就是55 //显示非模态对话框 .show() dlg->show(); //非阻塞 }); ui->dockWidget->show(); //浮动窗口 QPushButton* btn = new QPushButton("hello",this); //给下状态栏的左侧添加“hello”按钮 ui->statusBar->addWidget(btn); //下状态栏 QLabel* label = new QLabel("world",this); //给下状态栏“hello”按钮的左侧添加一个label显示内容为"world" ui->statusBar->addWidget(label); //ui->actionsave_as->setIcon(QIcon("D:\\1.jpg")); //给菜单栏下拉框中的"save as"添加图标,图标路径为:D:/1.jpg //添加完资源文件后, 可用下面这种添加方式 ui->actionsave_as->setIcon(QIcon(":/caidanlan/Image/1.jpg")); } MainWindow::~MainWindow() { delete ui; }
布局:
一般ui界面中,常用的是前三种布局垂直布局, 水平布局, 网格布局.
水平布局:使所选空间处于水平位置;
eg:在ui界面拖入两个label和两个Text Browser, 选中用户名和右边的Text Browser, 点击ui界面上方的水平布局,此时变为
;
但是不推荐使用,因为很容易水平变为右图这种; 顺序搞反后,不容易点击改变;
建议先放入一个widget窗口,再将用户名和Text Browser放入widget窗口,,选中widget窗口后,点击水平布局即可,
,密码和Text Browser2,同理, 两个按钮同理,最上面的label不用管,如图
,状态树的所属为:
垂直布局: 选中后, 点垂直布局, 变为:
;
此时拉拽ui界面, 按钮和框表会随之改变,要想让上方的label中的内容居中,可在对应label所属的属性框中找到,将水平的格式调为AlignVCenter,或者同理, 把label放入widget中, 再做一个水平布局;
加弹簧,弹簧也可以设置属性,sizeType中,Expanding,是默认可伸展的弹簧, Fixed是固定弹簧长度,
按钮固定大小:在按钮的属性框中,找到,将最大和最小的宽度设置为同一数值, 按钮大小就不会发生改变,或者两个按钮中间加个弹簧;
水平和垂直布局只能改变一行或一列, 效果图如下
网格布局: 打破用户名和密码的布局后,将这四个模块放入同一个widget,然后选择网格布局, 此时, , 将整个主窗口Widget垂直布局,将最大和最小的宽高都设置为192*173,此时:
,用户名左侧边框太宽,可以在主窗口Widget的属性中,找到
将layoutLeftMargin 设置为0. Top是顶部间距, Right是右侧边距, Bottom是底部边距, Spacing是控件直接的默认边距
控件介绍:
Layouts(布局): 垂直 水平 网格 表格
Spaces(弹簧): 水平 垂直
Buttons(按钮):
Push Button 普通按钮 三种信号:点击clicked ;按下pressed ; 释放 released; 可以给按钮设置图标
Radio Button 单选按钮 成组使用, ui界面的多个按钮只可点击一个.要想分两组使用, 将一组单选按钮放入Group Box框中. 比如性别 只有男女, 单选题.
Check Box 复选按钮 可以有多个选择, 没有选择限制. 比如爱好, 多选题. 信号是stateChanged, 使用lambda表达式时,()中要加参数 int state
connect(ui->checkBox, &QCheckBox::stateChanged, this, [=](int state)
{
QMessageBox::information(this, "checkbox", QString::number(state));
//QString::number(state) 把int型的state转为字符串
qDebug() << state; //选中复选框就打印2 未选就打印0
});
Item Views 比较高级, 老师不给教
Item Widget:
List Widget 数据一行一行的显示
ui->listWidget->addItem("hello,world!"); //QListWidgetItem* Item = new QListWidgetItem(QIcon("C:\\Users\\muchai\\Desktop\\1.jpg"),"l",ui->listWidget); //ui->listWidget->addItem(Item); ui->listWidget->addItem(new QListWidgetItem(QIcon("C:\\Users\\muchai\\Desktop\\1.jpg"),"1"));
Table Widget 数据如Excel表显示, 有行列表格线. 使用时需要指定行数 列数;
//1、指定行数 ui->tableWidget->setRowCount(100); //2、指定列数 ui->tableWidget->setColumnCount(3); //给每列起名字 QStringList list; list << "姓名" << "性别" << "年龄" ; //给每行起名字 QStringList list2; list2 << "人员1" << "人员2" << "人员3"; ui->tableWidget->setHorizontalHeaderLabels(list); ui->tableWidget->setVerticalHeaderLabels(list2);
,框中可以进行编辑。
Group Box(组框):一般会将Radio Button放入组框中。
Scroll Area(滚动区域):很小的窗口,显示很多的内容
Tool Box:抽屉一样的盒子,像QQ的分组列表,点开后,里面的好友被弹出,Page里面可以放控件,比如在Page1中放入本例的Group Box1,在Page2中放入本例的Scroll Area,
Tab Widget:选择页面,可以设置Tab按钮的位置,按钮文字。,
Stacked Widget(栈窗口):可以设置多个页面,通过连接按钮来切换页面;连接按钮时,可在Stacked Widget的属性栏中的QStackedWidget下的currentIndex的数值来查看窗口序号,同时这个序号也是连接外部按钮的槽函数的参数(此法的槽函数带int型的参数,与button的clicked的bool返回值不匹配,一般使用lambda表达式作为槽函数使用,在lambda的{}中写槽函数返回)。除了用序号连接外部按钮外,还可以根据Stacked Widget对应的窗口属性栏中QObject下的objectName来连接。
//connect(ui->btn_music, &QPushButton::clicked, ui->stackedWidget, &QStackedWidget::setCurrentIndex()); //信号与槽返回值类型不匹配,前者为bool 后者为int connect(ui->btn_music, &QPushButton::clicked, this, [=]() { ui->stackedWidget->setCurrentIndex(0); //参数可在ui界面的Stacked Widget的属性栏中的QStackedWidget下的currentIndex的数值来查看窗口序号 }); connect(ui->btn_tiktok, &QPushButton::clicked, this, [=]() { ui->stackedWidget->setCurrentWidget(ui->video); //video是Stacked Widget对应的窗口属性栏中QObject下的objectName }); connect(ui->btn_cale, &QPushButton::clicked, this, [=]() { ui->stackedWidget->setCurrentIndex(2); });
Dock Widget(浮动窗口):可以停靠在主窗口边框,还可以独立出来的窗口
Combo Box(下拉框):可以通过additem添加字符串,直接加字符串就行,或者图标加字符串
Font Combo Box(下拉框):字体下拉框
Label(文本图形框):可以放入图片(静态、动态)或文字;在Qt中 Picture不是图片,Pixmap才是图片!!
//ui->label->setPixmap(QPixmap(":/Image/1.jpg")); // QMovie movie(":/Image/yaw.gif"); //这样不行,因为movie对象创建在构造函数里面,movie对象创建出来后,构造函数里面的对象就被析构了,movie在播放的时候就已经被析构掉了,播放不出来画面. // ui->label->setMovie(&movie); // movie.start(); QMovie* movie = new QMovie(":/Image/yaw.gif"); ui->label->setMovie(movie); movie->start();
自定义控件: (封装SpinBox和水平进度条)
Spin Box的默认大小是0-99; 可通过 setRang(0,10000) 来设置Spin Box的大小;
本节就是将这两个控件(Spin Box & 滑动条)封装成一个控件(widget窗口), 方便后期重复使用;
步骤:
1. 先给项目中新建一个类
选中项目的名字, 鼠标右键 -> 添加新文件; 此时可以添加一个C++-> C++ Class, 但是C++ Class不带ui界面, 需要用代码来创建控件和编辑其属性;故此处用Qt -> Qt设计师界面类 -> Widget(空白界面,所有类的父类) -> 在<类名:>后面的LineEdit中, 给封装的类起个响亮的名字(SmallWidget), 头文件、源文件、界面文件自动修改 -> 完成;
2. 在smallwiddget.ui 中, 将Spin Box 和 水平滑动条放入, 将整个ui界面水平布局, 再将ui界面的窗口拖动到最小;
3. 此时在widget.ui中, 想用封装的自定义控件, 先在widget.ui中放入一个Widget控件(窗口), 鼠标右键单击刚放入的Widget窗口, 鼠标左键选择 "提升为..."; 在弹出的提升的窗口部件中,基类名称不用管, 在提升的类的名称中写入刚才创建的类的类名(SmallWidget), 写的时候注意大小写 ! 头文件不用管, 选中全局包含(在项目中的任何一个窗口都可以使用此控件) , 点击 "添加"按钮. 添加完成后, 提升的类会上升到上面的窗口, 此时点击对话框底部的"提升"按钮, 回到widget.ui界面, 此时可以看到ui界面的右侧属性栏中, widget的类名称已改变成SmallWidget, 而不再是QWidget. 此时再拉入一个widget_2,右键单击 -> 左键 "提升为" -> SmallWidget (全局包含的意义:可不限制窗口的将一个QWidget类提升为SmallWidget类)
此时的smallwidget.ui:
此时的widget.ui:
运行界面:
4. 因为把SmallWidget封装成了一个类, 在SmallWidget类中维护这两个控件要在smallwidget.cpp中的构造函数中编写代码, 进行Spin Box于滑动模块的对应的信号槽连接,使Spin Box增大,滑块随之移动, 滑块移动, Spin Box随之改变;
void (QSpinBox::*sigValeChange)(int) = &QSpinBox::valueChanged; //Qt5中不能直接将信号直接写入connect(因为valuechanged是个重载信号),需要定义一个指针; connect(ui->spinBox, sigValeChange, ui->horizontalSlider, &QSlider::setValue); //&QSlider里面没有对应的槽函数, 它的父类QAbstractSlider里面有setValue connect(ui->horizontalSlider, &QSlider::valueChanged, ui->spinBox, &QSpinBox::setValue);
5. 提供接口函数, 在smallwidget.h的public中,定义接口函数
int getValue(); //获取值
void SetValue(int value); //设置值
6. 在smallwidget.cpp中实现
void SmallWidget::SetValue(int value)
{
if(value > 0 && value < 100)
{
ui->spinBox->setValue(value);
}
}
int SmallWidget::getValue()
{
return ui->spinBox->value();
}
Qt样式表
在思想上很大程度来自于HTML的层叠式样式表(CSS), 通过调用 QWidget::setStyleSheet()或QApplication::setStyleSheet(),可为一个独立的子部件, 窗口, 甚至整个应用程序指定一个样式表; Qt样式表与CSS的语法几乎完全相同.
1. 语法基础: selector { attribute: value }
eg:(.cpp构造函数中) ui -> label -> setStyleSheet ("QLabel { color: red} "); //为一个独立的子部件指定一个样式表
(.cpp构造函数中) this -> setStyleSheet ("QLabel { color: red} "); //为一整个窗口指定一个样式表(本例中,所有的label都是红色)
(main.cpp中) a.setStyleSheet ("QLabel { color: red} "); //为整个应用程序指定一个样式表
当为整个应用程序指定一个样式表后,可对其中的一个或多个窗口或子部件进行属性修改; 为窗口指定样式表后, 也可修改其中的子部件属性;
选择器通常为一个类名 (eg: QComboBox), 属性(attribute)是一个样式表属性的名字, 值(value)是赋给该属性的值;
为方便使用, 可使用以下简化形式的样式表:
selector1, selector2, ... ... , selectorM
{
attribute1: value1;
attribute2: value2;
...
attributeN: valueN;
}
这种简化形式可以同时为与M个选择器相匹配的部件设置N种属性
QCheckBox, QComboBox, QSpinBox
{
color: red;
background-color: white;
font: bold;
}
这个规则设置了所有的QCheckBox, QComboBox和QSpinBox的前景色、背景色和字体
2. 方箱模型: 样式表中, 每个部件都可看成是一个由四个同心的矩形组成的箱体(方框套方框);
空白(margin): 空白区域位于边框外, 且总是透明
边框(border): 为部件提供了四周的框架, 其border-style属性可以设置为一些内置的框架风格,如inset, outset, solid, ridge;
填充(padding):填充在边框和内容区域之间, 提供了空白间隔.
内容(content): 对于一个平面部件, 例如一个空白、边框和填充都是0像素的部件而言,这四个矩形完全重合;
3. 前景和背景
前景用于绘制上面的文本, 可以通过color: 属性指定, 背景色用于绘制部件的填充矩形, 可以通过 background-color: 属性指定;
背景图片使用background-image 属性定义,用于绘制由background-origin指定的矩形区域(空白, 边框, 填充, 内容), 对齐和平铺方式可以通过background-position和background-repeat属性指定;
4. 可伸缩样式:
默认情况下, 通过background-image指定的背景图片会自动重复平铺,以覆盖部件的整个填充矩形,若我们想创建能够随着部件大小自动缩放,而不是平铺的背景,我们需要设置"边框图片". 通过border-image: 指定属性;
QPushButton{
border-width: 4px;
border-image: url(button.png); /*4 4 4 4 stretch stretch*/ } //注释里的是往里裁剪图片的属性, 设的越大,裁的越多;
5. 控制大小:min-width, min-height (不常用,因为可以直接在ui界面属性栏中控制)
6. 伪状态;
ui -> pushButton -> setStyleSheet("QPushButton
{"
"border: 2px outset green;" //按钮边框为绿
"}");
伪状态列表:
:checked button部件被选中
:disabled 部件被禁用
:enable 部件被启用
:fouces 部件获得焦点
:hover 鼠标位于部件上
:indeterminate checkbox或radiobutton被部分选中
:off 部件可以切换, 且处于off状态
:on 部件可以切换, 且处于on状态
:pressed 部件被鼠标按下
:unchecked button部件未被选中
ui -> pushButton -> setStyleSheet("QPushButton
{"
"border-image:url(:/1.jpg);" //按钮设置图标
"}");
ui -> pushButton -> setStyleSheet("QPushButton:hover
{"
"border-image:url(:/1.jpg);" //鼠标位于按钮上,按钮图标亮出
"}");
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!