C++QT入门_c++ qt

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

如果你需要这些资料,可以戳这里获取



#include “widget.h”
#include “ui_widget.h”
#include

Widget::Widget(QWidget *parent)
QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 重新更新
this->setWindowTitle(“hello world”);
// 设置 完成之后可以拉伸
this->resize(600,400);
// 设置固定大小
this->setFixedSize(QSize(600,400));

// QPushButton *button = new QPushButton;
// 设置父亲对象
// button->setParent(this);
// button->setText(“中国红!”);
// // 按钮移动
// button->move(50,50);
// // 设置按钮大小
// button->setFixedSize(QSize(400,400));
QPushButton *button2 = new QPushButton(“第二个按钮(关闭)”,this);
# 定义信号函数
connect(button2,&QPushButton::clicked,this,&Widget::print);

}

Widget::~Widget()
{
delete ui;
}

void Widget::print(){
qDebug()<<“hello world!”; // 槽函数实现
}


![image-20230619110112323](https://img-blog.csdnimg.cn/img_convert/6a6f0bd68c2623a16971002f241e1894.png)


##### 3.5 自定义信号


![image-20230619164419572](https://img-blog.csdnimg.cn/img_convert/635eb1e9d91998f7bb0a2659b8f2c6a1.png)


自定义信号槽需要注意的事项:


* 发送者和接收者都需要是QObject 的子类(当然,槽函数是全局函数、Lambda 表达式等无需接  
 收者的时候除外);
* 信号和槽函数返回值是void
* 信号只需要声明,不需要实现
* 槽函数需要声明也需要实现
* 槽函数是普通的成员函数,作为成员函数,会受到public、private、protected 的影响;
* 使用emit 在恰当的位置发送信号;
* 使用connect()函数连接信号和槽。
* 任何成员函数、static 函数、全局函数和Lambda 表达式都可以作为槽函数
* 信号槽要求信号和槽的参数一致,所谓一致,是参数类型一致。
* 如果信号和槽的参数不一致,允许的情况是,槽函数的参数可以比信号的少,即便如此,槽函  
 数存在的那些参数的顺序也必须和信号的前面几个一致起来。这是因为,你可以在槽函数中选  
 择忽略信号传来的数据(也就是槽函数的参数比信号的少)。


![image-20230619221022227](https://img-blog.csdnimg.cn/img_convert/2a544e81b58d324a38423115123f899c.png)


##### 3.6 信号槽拓展


* 一个信号可以和多个槽相连  
 如果是这种情况,这些槽会一个接一个的被调用,但是它们的调用顺序是不确定的。
* 多个信号可以连接到一个槽  
 只要任意一个信号发出,这个槽就会被调用
* 一个信号可以连接到另外的一个信号  
 当第一个信号发出时,第二个信号被发出。除此之外,这种信号-信号的形式和信号-槽的形式  
 没有什么区别。
* 槽可以被取消链接  
 这种情况并不经常出现,因为当一个对象delete 之后,Qt 自动取消所有连接到这个对象上面的  
 槽。
* 信号槽可以断开  
 利用disconnect 关键字是可以断开信号槽的
* 使用Lambda 表达式  
 在使用Qt5 的时候,能够支持Qt 5 的编译器都是支持Lambda 表达式的。  
 在连接信号和槽的时候,槽函数可以使用Lambda 表达式的方式进行处理。


重载信号时需要利用函数指针来确定执行的槽函数与信号函数



void (Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
void (Student:: *studentSignal)(QString) = &Student::treat;


##### 3.6 Qt4版本的信号槽写法



connect(zt,SIGNAL(hungry(QString)),st,SLOT(treat(QString)));


这里使用了SIGNAL 和SLOT 这两个宏,将两个函数名转换成了字符串。注意到connect()函数的  
 signal 和slot 都是接受字符串,一旦出现连接不成功的情况,Qt4 是没有编译错误的(因为一切  
 都是字符串,编译期是不检查字符串是否匹配),而是在运行时给出错误。这无疑会增加程序的不  
 稳定性。  
 **Qt5 在语法上完全兼容Qt4,而反之是不可以的。**


##### 3.7 Lambda 表达式


C++11 中的Lambda 表达式用于定义并创建匿名的函数对象,以简化编程工作。


Lambda表达式的基本构成:



capture mutable ->return-type
{
statement
}


* 函数对象参数;  
 [],标识一个Lambda 的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动  
 生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义Lambda 为止时Lambda 所  
 在作用范围内可见的局部变量(包括Lambda 所在类的this)。函数对象参数有以下形式:
	+ 空。没有使用任何函数对象参数。
	+ =。函数体内可以使用Lambda 所在作用范围内所有可见的局部变量(包括Lambda 所在类的  
	 this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
	+ &。函数体内可以使用Lambda 所在作用范围内所有可见的局部变量(包括Lambda 所在类的  
	 this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
	+ this。函数体内可以使用Lambda 所在类中的成员变量。
	+ a。将a 按值进行传递。按值进行传递时,函数体内不能修改传递进来的a 的拷贝,因为默  
	 认情况下函数是const 的。要修改传递进来的a 的拷贝,可以添加mutable 修饰符。
	+ &a。将a 按引用进行传递。
	+ a, &b。将a 按值进行传递,b 按引用进行传递。
	+ =,&a, &b。除a 和b 按引用进行传递外,其他参数都按值进行传递。
	+ &, a, b。除a 和b 按值进行传递外,其他参数都按引用进行传递。
* ② 操作符重载函数参数;  
 标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))  
 和按引用(如:(&a,&b))两种方式进行传递。
* 可修改标示符;  
 mutable 声明,这部分可以省略。按值传递函数对象参数时,加上mutable 修饰符后,可以修改  
 按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)。



QPushButton * myBtn = new QPushButton (this);
QPushButton * myBtn2 = new QPushButton (this);
myBtn2->move(100,100);
int m = 10;
connect(myBtn,&QPushButton::clicked,this,[m] ()mutable { m = 100 + 10; qDebug() << m; });
connect(myBtn2,&QPushButton::clicked,this,[=] () { qDebug() << m; });
qDebug() << m;


* 函数返回值;  
 ->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return 的地  
 方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。
* 是函数体;  
 {},标识函数的实现,这部分不能省略,但函数体可以为空。


###### 3.7.1 lambda传参(无参数)



auto fun=[](){
   qDebug()<<"hello world!222";
};
fun();

![image-20230620113414659](https://img-blog.csdnimg.cn/img_convert/0d82453fd7997321ec5f7381cff0e2bb.png)


###### 3.7.2 lambda 传参(有参数)



auto fun2=[](int a,int b){
   qDebug()<<"hello world!333";
   return a+b;
};
ClassIsOver();
qDebug()<<fun2(2,3);

###### 3.7.3 传值和传址



int a = 10;
auto fun3= [](int &a,int b){
   qDebug()<<"hello world!333";
   qDebug()<<"a==="<<a;
   a = 20;
   return a+b;
};

ClassIsOver();
qDebug()<<fun3(a,3);

![image-20230620113312085](https://img-blog.csdnimg.cn/img_convert/8fc4365e2fedf3dc96f0ed88f5bb0c00.png)


### 4. QMainWindow


#### 4.1 介绍


QMainWindow 是一个为用户提供主窗口程序的类,包含一个菜单栏(menu bar)、多个工具栏(toolbars)、多个铆接部件(dock widgets)、一个状态栏(status bar)及一个中心部件(central widget),是许多应用程序的基础,如文本编辑器,图片编辑器等。


![image-20230621000022651](https://img-blog.csdnimg.cn/img_convert/4fd1d6755796d8925e740cb267e17691.png)


分别对应菜单栏,菜单,菜单项


* 创建菜单栏,通过QMainWindow 类的menubar()函数获取主窗口菜单栏指针



//创建菜单栏:
#include
QMenuBar --> QMenuBar(QWidget *parent = Q_NULLPTR)
//添加菜单栏:
QMainWindow --> void setMenuBar(QMenuBar *menuBar)


* 创建菜单,调用QMenu 的成员函数addMenu 来添加菜单



//创建菜单:
#include
QMenu --> QMenu(const QString &title, QWidget *parent = Q_NULLPTR)
//添加菜单:
MenuBar --> QAction *addMenu(QMenu *menu)


* 创建菜单项,调用QMenu 的成员函数addAction 来添加菜单项



//创建菜单项:
#include
QAction --> QAction(const QString &text, QObject *parent = nullptr)
//添加菜单项:
QMenu --> addAction(const QAction *action)


Qt 并没有专门的菜单项类,只是使用一个QAction 类,抽象出公共的动作。当我们把QAction 对象添加到菜单,就显示成一个菜单项,添加到工具栏,就显示成一个工具按钮。用户可以通过点击菜单项、点击工具栏按钮、点击快捷键来激活这个动作。



#include “mainwindow.h”
#include //菜单栏
#include //菜单
#include //菜单项
#include
MainWindow::MainWindow(QWidget parent)
: QMainWindow(parent)
{
//窗口属性设置
******
this->setWindowTitle(“主窗口”);
this->setFixedSize(800, 600);
//创建菜单栏*******
//创建菜单栏
//注意:如果只有菜单栏,则在窗口处没有现象
QMenuBar *menu_bar = new QMenuBar(this);
this->setMenuBar(menu_bar);
千锋智能物联网学院
//创建菜单
QMenu *menu1 = new QMenu(“文件”, this);
menu_bar->addMenu(menu1);
QMenu *menu2 = new QMenu(“编辑”, this);
menu_bar->addMenu(menu2);
QMenu *menu3 = new QMenu(“构建”, this);
menu_bar->addMenu(menu3);
//创建菜单项
QAction *act1 = new QAction(“新建文件或项目”, this);
menu1->addAction(act1);
QAction *act2 = new QAction(“打开文件或项目”, this);
menu1->addAction(act2);
//添加分割线
menu1->addSeparator();
QAction *act3 = new QAction(“保存”, this);
menu1->addAction(act3);
QAction *act4 = new QAction(“另存为”, this);
menu1->addAction(act4);
QAction *act5 = new QAction(“复制”, this);
act5->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C));
menu2->addAction(act5);
QAction *act6 = new QAction(“粘贴”, this);
act6->setShortcut(QKeySequence(tr(“Ctrl+V”)));
menu2->addAction(act6);
QAction *act7 = new QAction(“剪切”, this);
menu2->addAction(act7);
//当单击菜单项时,做出相应的处理
connect(act5, &QAction::triggered, [=]{
qDebug()<<“复制正在执行”;
});
connect(act6, &QAction::triggered, [=]{qDebug()<<“粘贴正在执行”;
});
}
MainWindow::~MainWindow()
{
}


![image-20230621001246177](https://img-blog.csdnimg.cn/img_convert/6740b16b05ecd464119787951b6f790f.png)


#### 4.2 工具栏


主窗口的工具栏上可以有多个工具条,通常采用一个菜单对应一个工具条的的方式,也可根据需要进行工具条的划分。



//创建工具栏:
#include
QToolBar --> QToolBar(QWidget *parent = Q_NULLPTR)
//添加工具栏:
QMainWindow -->
void addToolBar(QToolBar *toolbar)
void addToolBar(Qt::ToolBarArea area, QToolBar *toolbar)
Qt::LeftToolBarArea 左边显示
Qt::RightToolBarArea 右边显示
Qt::TopToolBarArea 上边显示
Qt::BottomToolBarArea 下边显示


直接调用QMainWindow 类的addToolBar()函数获取主窗口的工具条对象,每增加一个工具条  
 都需要调用一次该函数。


* 插入属于工具条的动作,即在工具条上添加操作。  
 通过QToolBar 类的addAction 函数添加。
* 工具条是一个可移动的窗口,它的停靠区域由QToolBar 的allowAreas 决定,包括:
* Qt::LeftToolBarArea 停靠在左侧
* Qt::RightToolBarArea 停靠在右侧
* Qt::TopToolBarArea 停靠在顶部
* Qt::BottomToolBarArea 停靠在底部
* Qt::AllToolBarAreas 以上四个位置都可停靠
* 使用setAllowedAreas()函数指定停靠区域:  
 setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea)
* 使用setMoveable()函数设定工具栏的可移动性:  
 setMoveable(false)//工具条不可移动, 只能停靠在初始化的位置上



//创建工具栏
//注意:工具栏可以添加多个
QToolBar *toolbar = new QToolBar(this);
//将工具栏添加到窗口
//this->addToolBar(toolbar);//默认在最上面显示
this->addToolBar(Qt::LeftToolBarArea, toolbar); //设置默认在左边显示
//工具栏添加菜单项和分割线
QAction *act_tool1 = new QAction(“欢迎”, this);
QAction *act_tool2 = new QAction(“编辑”, this);
toolbar->addAction(act_tool1);
toolbar->addSeparator();
toolbar->addAction(act_tool2);
//设置工具栏的浮动状态,true:可以悬浮在窗口false:不可以
toolbar->setFloatable(false);
//设置运行工具栏的位置,设置为左边或者右边
toolbar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);


#### 4.3 状态栏


* 派生自QWidget 类,使用方法与QWidget 类似,QStatusBar 类常用成员函数:状态栏也只能最多有一个



创建状态栏:
QStatusBar -->
将控件添加到左边栏
void addWidget(QWidget *widget, int stretch = 0)
将控件添加到右边栏
void addPermanentWidget(QWidget *widget, int stretch = 0)
添加状态栏:
QMainWindow --> void setStatusBar(QStatusBar *statusbar)
//创建状态栏
//状态栏只能有一个
QStatusBar *statusbar = new QStatusBar(this);
//添加状态栏
this->setStatusBar(statusbar);
//给状态栏中添加文字信息或者按钮=
QLabel *label1 = new QLabel(“左边信息”, this);
statusbar->addWidget(label1);
QLabel *label2 = new QLabel(“右边信息”, this);
statusbar->addPermanentWidget(label2);
QPushButton *button = new QPushButton(“设置”, this);
statusbar->addWidget(button);


#### 4.4 铆接部件



创建铆接部件:
QDockWidget -->
QDockWidget(const QString &title, QWidget *parent = Q_NULLPTR)
添加铆接部件:
QMainWindow -->
void addDockWidget(Qt::DockWidgetArea area, QDockWidget
*dockwidget)
Qt::LeftDockWidgetArea 左边
Qt::RightDockWidgetArea 右边
Qt::TopDockWidgetArea 上边
Qt::BottomDockWidgetArea 下边
//创建铆接部件
QDockWidget *dockwidget = new QDockWidget(“这是一个铆接部件”, this);
this->addDockWidget(Qt::TopDockWidgetArea, dockwidget);


#### 4.5 中心部件


除了以上几个部件,中心显示的部件都可以作为核心部件,例如一个记事本文件,可以利用QTextEdit 做核心部件



添加中心部件:
QMainWindow --> void setCentralWidget(QWidget *widget)
QTextEdit *edit = new QTextEdit(“文本编辑器”, this);
this->setCentralWidget(edit);


#### 4.6 资源文件


Qt 资源系统是一个跨平台的资源机制,用于将程序运行时所需要的资源以二进制的形式存储于可执行文件内部。如果你的程序需要加载特定的资源(图标、文本翻译等),那么,将其放置在资源文件中,就再也不需要担心这些文件的丢失。也就是说,如果你将资源以资源文件形式存储,它是会编译到可执行文件内部。使用Qt Creator 可以很方便地创建资源文件。我们可以在工程上点右键,选择“添加新文件…”,可以在Qt 分类下找到“Qt 资源文件”:


![image-20230621005359980](https://img-blog.csdnimg.cn/img_convert/3fc5230a0d679a44b1409449c34d9998.png)


#### 4.7 增加背景图



this->setAutoFillBackground(true);
//创建图片控件
QPixmap pix = = = QPixmap(“:/image/butterfly.png”). scaled(this->size());
// pix.load(“😕/image/butterfly.png”);
QPalette palette;
palette.setBrush(QPalette:: Background,QBrush(pix));
this->setPalette(palette);
this->setAutoFillBackground(true);
//创建图片控件
QPixmap pix = QPixmap(“:/image/butterfly.png”). scaled(this->size());
// pix.load (“:/image/butterfly.png”);
QPalette palette;
palette.setBrush(QPalette:: Background, QBrush(pix));
this->setPalette(palette);


### 5. 对话框


#### 5.1 基本概念


对话框是GUI 程序中不可或缺的组成部分。很多不能或者不适合放入主窗口的功能组件都必须放在对话框中设置。对话框通常会是一个顶层窗口,出现在程序最上层,用于实现短期任务或者简洁的用户交互。


Qt 中使用QDialog 类实现对话框。就像主窗口一样,我们通常会设计一个类继承QDialog。QDialog(及其子类,以及所有Qt::Dialog 类型的类)的对于其parent 指针都有额外的解释:如果parent  
 为NULL,则该对话框会作为一个顶层窗口,否则则作为其父组件的子对话框(此时,其默认出现的位置是parent 的中心)。顶层窗口与非顶层窗口的区别在于,顶层窗口在任务栏会有自己的位置,而非顶层窗口则会共享其父组件的位置。对话框分为模态对话框和非模态对话框。


* 模态对话框,就是会阻塞同一应用程序中其它窗口的输入。  
 模态对话框很常见,比如“打开文件”功能。你可以尝试一下记事本的打开文件,当打开文件  
 对话框出现时,我们是不能对除此对话框之外的窗口部分进行操作的。
* 与此相反的是非模态对话框,例如查找对话框,我们可以在显示着查找对话框的同时,继续对  
 记事本的内容进行编辑。


#### 5.2 标准对话框


所谓标准对话框,是Qt内置的一系列对话框,用于简化开发。事实上,有很多对话框都是通用的,比如打开文件、设置颜色、打印设置等。这些对话框在所有程序中几乎相同,因此没有必要在每一个程序中都自己实现这么一个对话框。Qt 的内置对话框大致分为以下几类:


* QColorDialog: 选择颜色;
* QFileDialog: 选择文件或者目录;
* QFontDialog: 选择字体;
* QInputDialog: 允许用户输入一个值,并将其值返回;
* QMessageBox: 模态对话框,用于显示信息、询问问题等;
* QPageSetupDialog: 为打印机提供纸张相关的选项;
* QPrintDialog: 打印机配置;
* QPrintPreviewDialog:打印预览;
* QProgressDialog: 显示操作过程。


##### 5.2.1 模态对话框



QDialog dialog;
dialog.setWindowTitle(tr(“Hello, dialog!”));
dialog.exec();


##### 5.2.2 非模态对话框



QDialog dialog(this);
dialog.setWindowTitle(tr(“Hello, dialog!”));
dialog.show();


是不是事与愿违?对话框竟然一闪而过!这是因为,show()函数不会阻塞当前线程,对话框会显示出来,然后函数立即返回,代码继续执行。注意,dialog 是建立在栈上的,show()函数返回,MainWindow::open()函数结束,dialog 超出作用域被析构,因此对话框消失了。知道了原因就好改了,我们将dialog 改成**堆上建立**,当然就没有这个问题了:



QDialog *dialog = new QDialog;
dialog->setWindowTitle(tr(“Hello, dialog!”));
dialog->show();


上面的代码是有问题的:dialog 存在内存泄露!dialog 使用new 在堆上分配空间,却一直没有delete。


解决方案也很简单:将MainWindow 的指针赋给dialog 即可。还记得我们前面说过的Qt 的对象系统吗?不过,这样做有一个问题:如果我们的对话框不是在一个界面类中出现呢?由于QWidget 的parent必须是QWidget 指针,那就限制了我们不能将一个普通的C++ 类指针传给Qt 对话框。另外,如果对内存占用有严格限制的话,当我们将主窗口作为parent 时,主窗口不关闭,对话框就不会被销毁,所以会一直占用内存。在这种情景下,我们可以设置dialog 的WindowAttribute:



QDialog *dialog = new QDialog;
dialog->setAttribute(Qt::WA_DeleteOnClose); // 在这里
dialog->setWindowTitle(tr(“Hello, dialog!”));
dialog->show();


setAttribute()函数设置对话框关闭时,自动销毁对话框。


#### 5.3 消息对话框


QMessageBox 用于显示消息提示。我们一般会使用其提供的几个static 函数:


* 显示关于对话框



void about(QWidget * parent, const QString & title, const QString & text)


这是一个最简单的对话框,其标题是title,内容是text,父窗口是parent。对话框只有一个OK 按钮。


* 显示关于Qt 对话框。该对话框用于显示有关Qt 的信息。



void aboutQt(QWidget * parent, const QString & title = QString()):


* 与QMessageBox::critical()类似,不同之处在于这个对话框提供一个普通信息图标。



StandardButton information(QWidget * parent,
const QString & title,
const QString & text,
StandardButtons buttons = Ok,
StandardButton defaultButton


* 与QMessageBox::critical ()类似,不同之处在于这个对话框提供一个问号图标,并且其显示的按钮是“是”和“否”。



StandardButton question(QWidget * parent,const QString & title,
const QString & text,
StandardButtons buttons = StandardButtons( Yes | No ),
StandardButton defaultButton = NoButton)


* 与QMessageBox::critical()类似,不同之处在于这个对话框提供一个黄色叹号图标。



StandardButton warning(QWidget * parent,
const QString & title,
const QString & text,
StandardButtons buttons = Ok,
StandardButton defaultButton = NoButton)


QMessageBox演示



if (QMessageBox::Yes == QMessageBox::question(this,
tr(“Question”), tr(“Are you OK?”),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes))
{
QMessageBox::information(this, tr(“Hmmm…”),
tr(“I’m glad to hear that!”));
}
else
{
QMessageBox::information(this, tr(“Hmmm…”),
tr(“I’m sorry!”));
}


这个对话框的父窗口是this。QMessageBox 是QDialog 的子类,这意味着它的初始显示位置将会是在parent 窗口的中央。 第二个参数是对话框的标题。第三个参数是我们想要显示的内容。 第四个参数是关联的按键类型,我们可以使用或运算符(|)指定对话框应该出现的按钮。比如我们希望是一个Yes 和一个No。 最后一个参数指定默认选择的按钮。这个函数有一个返回值,用于确定用户点击的是哪一个按钮。按照我们的写法,应该很容易的看出,这是一个模态对话框,因此我们可以直接获取其返回值。QMessageBox 类的static 函数优点是方便使用,缺点也很明显:非常不灵活。


我们只能使用简单的几种形式。为了能够定制QMessageBox 细节,我们必须使用QMessageBox 的属性设置API。如果我们希望制作一个询问是否保存的对话框,我们可以使用如下的代码:



QMessageBox msgBox;
msgBox.setText(tr(“The document has been modified.”));
msgBox.setInformativeText(tr(“Do you want to save your changes?”));
msgBox.setDetailedText(tr(“Differences here…”));
msgBox.setStandardButtons(QMessageBox::Save
| QMessageBox::Discard
| QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
switch (ret)
{
case QMessageBox::Save:
qDebug() << “Save document!”;
break;
case QMessageBox::Discard:
qDebug() << “Discard changes!”;
break;
case QMessageBox::Cancel:
qDebug() << “Close document!”;
break;
}


msgBox 是一个建立在栈上的QMessageBox 实例。我们设置其主要文本信息为“The document has beenmodified.”,informativeText 则是会在对话框中显示的简单说明文字。下面我们使用了一个detailedText,也就是详细信息,当我们点击了详细信息按钮时,对话框可以自动显示更多信息。我们自己定义的对话框的按钮有三个:保存、丢弃和取消。然后我们使用了exec()是其成为一个模态对话框,根据其返回值进行相应的操作。


### 6.布局管理器


GUI 界面,归根结底,就是一堆组件的叠加。我们创建一个窗口,把按钮放上面,把图标放上面,这样就成了一个界面。在放置时,组件的位置尤其重要。我们必须要指定组件放在哪里,以便窗口能够按照我们需要的方式进行渲染。这就涉及到组件定位的机制。


Qt 提供了两种组件定位机制:**绝对定位**和**布局定位**。


* 绝对定位就是一种最原始的定位方法:给出这个组件的坐标和长宽值。
* 这样,Qt 就知道该把组件放在哪里以及如何设置组件的大小。但是这样做带来的一个问题是,如果用户改变了窗口大小,比如点击最大化按钮或者使用鼠标拖动窗口边缘,采用绝对定位的组件是不会有任何响应的。这也很自然,因为你并没有告诉Qt,在窗口变化时,组件是否要更新自己以及如何更新。或者,还有更简单的方法:禁止用户改变窗口大小。但这总不是长远之计。
* 布局定位:你只要把组件放入某一种布局,布局由专门的布局管理器进行管理。当需要调整大小或者位置的时候,Qt 使用对应的布局管理器进行调整。布局定位完美的解决了使用绝对定位的缺陷。


Qt 提供的布局中以下三种是我们最常用的:


* QHBoxLayout:按照水平方向从左到右布局;
* QVBoxLayout:按照竖直方向从上到下布局;
* QGridLayout:在一个网格中进行布局,类似于HTML 的table;


#### 6.1 系统布局


系统给我们提供的布局的控件


![image-20230621211019387](https://img-blog.csdnimg.cn/img_convert/586cc7fe06f779800cd72cf318064691.png)


#### 6.2 利用widget 做布局


第二种布局方式是利用控件里的widget 来做布局,在Containers 中


![image-20230621211211302](https://img-blog.csdnimg.cn/img_convert/65304a148eab5d33cfa5bce9954719fd.png)


在widget 中的控件可以进行水平、垂直、栅格布局等操作,比较灵活。再布局的同时我们需要灵活运用弹簧的特性让我们的布局更加的美观,下面是一个登陆窗口,利用widget 可以搭建出如下登陆界面:


![image-20230621211307819](https://img-blog.csdnimg.cn/img_convert/3a31c601bb38398041cdb677081abf94.png)


### 7.常用控件


Qt 为我们应用程序界面开发提供的一系列的控件,下面我们介绍两种最常用一些控件,所有控件的使用方法我们都可以通过帮助文档获取。


#### 7.1 QLabel


QLabel 是我们最常用的控件之一,其功能很强大,我们可以用来显示文本,图片和动画等。


##### 7.1.1 显示文字(普通文本、html)


通过QLabel 类的setText 函数设置显示的内容:



void setText(const QString &)


* 可以显示普通文本字符串



QLable *label = new QLable;
label->setText(“Hello, World!”);


* 可以显示HTML 格式的字符串  
 比如显示一个链接:



QLabel * label = new QLabel(this);
label ->setText(“Hello, World”);
label ->setText(“

<a href=“https://www.baidu.com”>百度一下

”);
label ->setOpenExternalLinks(true);


其中setOpenExternalLinks()函数是用来设置用户点击链接之后是否自动打开链接,如果参数指定为true 则会自动打开。


##### 7.1.2 显示图片


可以使用QLabel 的成员函数setPixmap 设置图片



void setPixmap(const QPixmap &)


首先定义QPixmap 对象,加载图片,设置到QLabel



QPixmap pixmap;
pixmap.load(“:/Image/boat.jpg”);
QLabel *label = new QLabel;
label.setPixmap(pixmap);


##### 7.1.3 显示动画


可以使用QLabel 的成员函数setMovie 加载动画,可以播放gif 格式的文件



void setMovie(QMovie * movie)


首先定义QMovied 对象,并初始化:



QMovie *movie = new QMovie(“:/Mario.gif”);



//播放加载的动画:
movie->start();
//将动画设置到QLabel 中:
QLabel *label = new QLabel;
label->setMovie(movie);


#### 7.2 QLineEdit


Qt 提供的单行文本编辑框。


##### 7.2.1 设置/获取内容


获取编辑框内容使用text(),函数声明如下:



QString text() const


* 设置编辑框内容



void setText(const QString &)


##### 7.2.2 设置显示模式


使用QLineEdit 类的setEchoMode () 函数设置文本的显示模式,函数声明:



void setEchoMode(EchoMode mode)


EchoMode 是一个枚举类型,一共定义了四种显示模式:


* QLineEdit::Normal 模式显示方式,按照输入的内容显示。
* QLineEdit::NoEcho 不显示任何 内容,此模式下无法看到用户的输入。
* QLineEdit::Password 密码模式,输入的字符会根据平台转换为特殊字符。
* QLineEdit::PasswordEchoOnEdit 编辑时显示字符否则显示字符作为密码。  
 另外,我们再使用QLineEdit 显示文本的时候,希望在左侧留出一段空白的区域,那么,就可以使  
 用QLineEdit 给我们提供的setTextMargins 函数:

 

void setTextMargins(int left, int top, int right, int bottom)

 用此函数可以指定显示的文本与输入框上下左右边界的间隔的像素数。



// smallwidget.h
class SmallWidget : public QWidget
{
Q_OBJECT
public:
explicit SmallWidget(QWidget parent = 0);
signals:
public slots:
private:
QSpinBox
spin;
QSlider* slider;
};
// smallwidget.cpp
SmallWidget::SmallWidget(QWidget parent) : QWidget(parent)
{
spin = new QSpinBox(this);
slider = new QSlider(Qt::Horizontal, this);
// 创建布局对象
QHBoxLayout
layout = new QHBoxLayout;
// 将控件添加到布局中
layout->addWidget(spin);
layout->addWidget(slider);
// 将布局设置到窗口中
setLayout(layout);
// 添加消息响应
connect(spin,
static_cast<void (QSpinBox:😗)(int)>(&QSpinBox::valueChanged),slider, &QSlider::setValue);
connect(slider, &QSlider::valueChanged,
spin, &QSpinBox::setValue);
}


![image-20230621225927166](https://img-blog.csdnimg.cn/img_convert/d0ec5c44c3a88a24d513c418758ae03c.png)


### 8. Qt 消息机制和事件


#### 8.1 事件处理过程


事件(event)是由系统或者Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。


一些事件在对用户操作做出响应时发出,如键盘事件等;另一些事件则是由系统自动发出,如计时器事件。事件处理过程:


1. 在Qt 内部,Qt 通过QApplication::exec()启动的主事件循环不停的抓取事件队列中的事件。
2. 当事件发生时,Qt 将创建一个事件对象。Qt 中所有事件类都继承于QEvent。
3. 在事件对象创建完毕后,Qt 将这个事件对象传递给QObject 的event()函数。event()函数并不直接处理事件,  
 而是按照事件对象的类型分派给特定的事件处理函数(event handler)。  
 event()函数主要用于事件的分发:


#### 8.2 常用事件处理


在所有控件的父类QWidget 中,定义了很多事件处理的回调函数。这些函数都是protected virtual 的,也就是说,我们可以在子类中重新实现这些函数。实现函数的要遵循虚函数的语法规则,自定义的类中保证函数名、参数的一致性。


##### 8.2.1 鼠标事件



//重写父类的虚函数
protected:
virtual void mousePressEvent(QMouseEvent *); //鼠标点击事件
virtual void mouseReleaseEvent(QMouseEvent *); //鼠标抬起事件
virtual void mouseDoubleClickEvent(QMouseEvent *); //鼠标双击事件
virtual void mouseMoveEvent(QMouseEvent *); //鼠标移动事件


##### 8.2.2 滚轮事件(QWheelEvent)



//virtual void wheelEvent(QWheelEvent *); //鼠标滚轮滑动
//鼠标滚轮滑动
void Widget::wheelEvent(QWheelEvent *e)
{
if(e->orientation()== Qt::Vertical) //如果方向是垂直
{
QPoint point = e->angleDelta();
QString str = QString(“滚轮垂直滑动(%1, %2)”)
.arg( point.x() ).arg(point.y());
ui->label->setText(str);
}
}


##### 8.2.3 键盘事件(QKeyEvent)



//virtual void keyPressEvent(QKeyEvent *); //键盘按下事件
//virtual void keyReleaseEvent(QKeyEvent *); //键盘抬起事件
//键盘按下事件
void Widget::keyPressEvent(QKeyEvent *e)
{
QString str;
switch(e->modifiers()) //修饰键盘
{
case Qt::ControlModifier:
str = “Ctrl+”;
break;
case Qt::AltModifier:
str = “Alt+”;
break;
}
switch(e->key()) //普通键
{
case Qt::Key_Left:
str += “Left_Key Press”;
break;
case Qt::Key_Right:
str += “Rigth_Key Press”;
break;
case Qt::Key_Up:
str += “Up_Key Press”;
break;
case Qt::Key_Down:
str += “Down_Key Press”;
break;
case Qt::Key_Z:
str += “Z_Key Press”;
break;
}
ui->label->setText(str);
}


##### 8.2.4 大小改变事件(QResizeEvent)



当窗口大小发生变化时被调用,参考代码:
//virtual void resizeEvent(QResizeEvent *); //大小改变事件
//大小改变事件
void Widget::resizeEvent(QResizeEvent *e)
{
//变化前的窗口大小
qDebug() << "e->oldSize() = " << e->oldSize();
//变化后的窗口大小
qDebug() << "e->size() = " << e->size();
}


##### 8.2.5 进入离开区域事件(enterEvent、leaveEvent)



//virtual void enterEvent(QEvent *); //进入事件
//virtual void leaveEvent(QEvent *); //离开事件
//进入事件
void Widget::enterEvent(QEvent *)
{qDebug() << “enterEvent”;
}
//离开事件
void Widget::leaveEvent(QEvent *)
{
qDebug() << “leaveEvent”;
}


### 9 绘图


#### 9.1 Qt绘图机制


Qt 的绘图机制为屏幕显示和打印显示提供了统一的API 接口,主要有三部分组成:QPainter 类、QPaintDevice  
 类和QPaintEngine 类  
 l QPainter 类提供了画图操作的各种接口,可方便地绘制各种各样的图形。  
 l QPaintDevice 类提供可用于画图的空间,及画图容器。  
 lPaintEngine 类是抽象类,提供了QPainter 如何在指定的平台上给指定的设备绘画的抽象接口,对开发者而言,  
 一般不会用到。


![image-20230621233533906](https://img-blog.csdnimg.cn/img_convert/1a32b53726a0e92e662f8c07ae937cf6.png)


#### 9.2 绘图事件



void Widget::paintEvent(QPaintEvent *e)
{
qDebug()<<“in paintEvent”<<“recet”<rect(); //得到需要重新绘制的区域
QPainter paint(this); //定义画家(请了一个画家来画画),画在主窗口上
//画家画图片,作为背景图片
paint.drawPixmap(0,0,this->width(),this->height(),
QPixmap(“…/Image/bk.jpg”));
QPen pen; //定义一只画笔
pen.setColor(QColor(255,0,255)); //设置画笔的颜色
pen.setWidth(5); //设置画笔的宽度
pen.setStyle(Qt::DashDotLine); //设置画笔线条的风格
paint.setPen(pen); //画家使用这只画笔
paint.drawLine(30,30,500,30);//画家画水平的线条
paint.drawLine(30,30,30,500);//画家画垂直的线条
pen.setColor(Qt::yellow);//设置画笔的颜色
pen.setStyle(Qt::SolidLine);//设置画笔线条的风格
pen.setWidth(3);//设置线条的宽度
paint.setPen(pen);//画家使用这只画笔
QBrush brush(Qt::blue);//定义一把蓝色的画刷
brush.setStyle(Qt::DiagCrossPattern);//设置画刷的风格
paint.setBrush(brush);//画家使用这把画刷
paint.drawRect(50,50,150,200);//画家画矩形
paint.setPen(QPen());
paint.setBrush(QBrush(QColor(255,187,255),Qt::Dense3Pattern));
paint.drawEllipse(280,60,180,250);//画家画椭圆
}


#### 9.3 刷新绘图区域



//绘图事件
void Widget::paintEvent(QPaintEvent *)
{
QPainter p(this); //在窗口上绘图
p.drawPixmap(x,200,100,100,QPixmap(“…/Image/face.png”));
p.drawPixmap(i,j,100,100,QPixmap(“…/Image/face.png”));
}
void Widget::on_pushButton_clicked()
{
x += 20;
if(x > this->width())
{
x = 0;
}
this->update(); //刷新绘图区
}
void Widget::mousePressEvent(QMouseEvent *e)
{i = e->pos().x();
j = e->pos().y();
this->update(); //刷新绘图区域
}

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

如果你需要这些资料,可以戳这里获取

tStyle(Qt::SolidLine);//设置画笔线条的风格
pen.setWidth(3);//设置线条的宽度
paint.setPen(pen);//画家使用这只画笔
QBrush brush(Qt::blue);//定义一把蓝色的画刷
brush.setStyle(Qt::DiagCrossPattern);//设置画刷的风格
paint.setBrush(brush);//画家使用这把画刷
paint.drawRect(50,50,150,200);//画家画矩形
paint.setPen(QPen());
paint.setBrush(QBrush(QColor(255,187,255),Qt::Dense3Pattern));
paint.drawEllipse(280,60,180,250);//画家画椭圆
}


#### 9.3 刷新绘图区域



//绘图事件
void Widget::paintEvent(QPaintEvent *)
{
QPainter p(this); //在窗口上绘图
p.drawPixmap(x,200,100,100,QPixmap(“…/Image/face.png”));
p.drawPixmap(i,j,100,100,QPixmap(“…/Image/face.png”));
}
void Widget::on_pushButton_clicked()
{
x += 20;
if(x > this->width())
{
x = 0;
}
this->update(); //刷新绘图区
}
void Widget::mousePressEvent(QMouseEvent *e)
{i = e->pos().x();
j = e->pos().y();
this->update(); //刷新绘图区域
}

[外链图片转存中…(img-oBWY6upj-1715765259089)]
[外链图片转存中…(img-phxBXR6J-1715765259089)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

如果你需要这些资料,可以戳这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值