C++QT入门_c++ qt

img
img

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

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

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

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

常见GUI:

QT:支持多平台开发;支持css;面向对象特性体现突出;发展趋势良好。

MFC:只能在windows开发;运行程序效率高;库的安全性好;

1.2 QT的发展史
  • 1991 年Qt 最早由奇趣科技开发
  • 1996 年进入商业领域,它也是目前流行的Linux 桌面环境KDE 的基础
  • 2008 年奇趣科技被诺基亚公司收购,Qt 称为诺基亚旗下的编程语言
  • 2012 年Qt 又被Digia 公司收购
  • 2014 年4 月跨平台的集成开发环境Qt Creator3.1.0 发布,同年5 月20 日配发了Qt5.3 正式版,
  • 至此Qt 实现了对iOS、Android、WP 等各平台的全面支持。
  • 当前Qt 最新版本为5.13.2(2019.12 之前)
1.3 支持的平台
  • Windows – XP、Vista、Win7、Win8、Win2008、Win10
  • Uinux/X11 – Linux、Sun Solaris、HP-UX、Compaq Tru64 UNIX、IBM AIX、SGI IRIX、FreeBSD、
    BSD/OS、和其他很多X11 平台
  • Macintosh – Mac OS X
  • Embedded – 有帧缓冲支持的嵌入式Linux 平台,Windows CE
1.4 QT版本

Qt 按照不同的版本发行,分为商业版和开源版

  • 商业版:商业软件提供开发,他们提供传统商业软件发行版,并且提供在商业有效期内的免费升级和技术支持服务。
  • 开源版(LGPL):开源的LGPL 版本,为了开发自有而设计的开放源码软件,它提供了和商业版本同样的功能,在GNU 通用公共许可下,它是免费的。
1.5 Qt 的下载与安装
  • http://www.qt.io/download-open-source/
  • http://download.qt.io/archive/qt/

image-20230617192318611

image-20230617192628524

按照默认安装即可
Qt 对不同的平台提供了不同版本的安装包,可根据实际情况自行下载安装,本文档使用
qt-opensource-windows-x86-mingw530-5.13.0 版本进行讲解(32 位和64 位均可安装)

1.6 QT的优点
  • 跨平台,几乎支持所有的平台
  • 接口简单,容易上手,学习QT 框架对学习其他框架有参考意义。
  • 一定程度上简化了内存回收机制
  • 开发效率高,能够快速的构建应用程序。
  • 有很好的社区氛围,市场份额在缓慢上升。
  • 可以进行嵌入式开发。
1.7 成功案例
  • Linux 桌面环境KDE
  • Skype 网络电话
  • Google Earth 谷歌地图
  • VLC 多媒体播放器
  • VirtualBox 虚拟机软件
  • 咪咕音乐
  • WPS Office
  • 极品飞车

2. 创建QT项目

2.1 使用向导创建
  • 打开Qt Creator 界面选择
  • New Project 或者选择菜单栏【文件】-【新建文件或项目】菜单项
  • 弹出New Project 对话框,选择Qt Widgets Application

image-20230617205216497

image-20230617205254631

image-20230617215755059

2.2 手动创建
  • 添加一个空项目

image-20230617220114633

  • 选择【choose】进行下一步。设置项目名称和路径—> 选择编译套件–> 修改类信息–> 完成(步骤同上),生成一个空项目。在空项目中添加文件:在项目名称上单击鼠标右键弹出右键菜单,选择【添加新文件】

image-20230617220131998

  • 弹出新建文件对话框

image-20230617220150476

2.3 .pro 文件

在使用Qt 向导生成的应用程序.pro 文件格式如下:

QT += core gui //包含的模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets //大于Qt4 版本才包含widget 模块
TARGET = QtFirst //应用程序名生成的.exe 程序名称
TEMPLATE = app //模板类型应用程序模板
SOURCES += main.cpp //源文件
mywidget.cpp
HEADERS += mywidget.h //头文件

.pro 就是工程文件(project),它是qmake 自动生成的用于生产makefile 的配置文件。.pro 文件的
写法如下:

  • 注释
    从“#”开始,到这一行结束。
  • 模板变量告诉qmake 为这个应用程序生成哪种makefile。下面是可供使用的选择:TEMPLATE = app,app -建立一个应用程序的makefile。这是默认值,所以如果模板没有被指定,这个将被使用。
  • lib - 建立一个库的makefile。
  • vcapp - 建立一个应用程序的VisualStudio 项目文件。
  • vclib - 建立一个库的VisualStudio 项目文件。
  • subdirs -这是一个特殊的模板,它可以创建一个能够进入特定目录并且为一个项目文件生成makefile 并且为它调用make 的makefile。
#指定生成的应用程序名:
TARGET = QtDemo
#工程中包含的头文件
HEADERS += include/painter.h
#工程中包含的.ui 设计文件
FORMS += forms/painter.ui
#工程中包含的源文件
SOURCES += sources/main.cpp sources
#工程中包含的资源文件
RESOURCES += qrc/painter.qrc
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
这条语句的含义是,如果QT_MAJOR_VERSION 大于4(也就是当前使用的Qt5 及更高版本)需要
增加widgets 模块。如果项目仅需支持Qt5,也可以直接添加“QT += widgets”一句。不过为
了保持代码兼容,最好还是按照QtCreator 生成的语句编写。
#配置信息
CONFIG 用来告诉qmake 关于应用程序的配置信息。
CONFIG += c++11 //使用c++11 的特性
在这里使用“+=”,是因为我们添加我们的配置选项到任何一个已经存在中。这样做比使用“=”那
样替换已经指定的所有选项更安全。

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 重新更新
    this->setWindowTitle("hello world"); // 更改UI内容
    this->resize(600,400);
}

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



2.4 设置父对象
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>

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

    QPushButton *button =  new QPushButton;
    // 设置父亲对象
    button->setParent(this);
}

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



image-20230618001225199

2.5 按钮设置属性
2.5.1 按钮设置文本
button->setText("红红红!");

2.5.2 设置移动
button->move(50,50);

2.5.3 设置固定大小
button->setFixedSize(QSize(400,400));

2.6 另外一种创建按钮方式
2.6.1 构造时创建
      QPushButton *button2 = new QPushButton("第二个按钮",this); // 包括设置文本和父对象

2.6.2 初始化后设置与构造函数设置的区别
  • 初始化后设置,显示为窗口的默认大小
  • 构造函数设置会导致窗口大小为按钮大小,需要重新设置大小。
2.7 对象模型(对象树)

在Qt中创建对象的时候会提供一个Parent对象指针,下面来解释这个parent到底
是干什么的。

  • QObject是以对象树的形式组织起来的。

当你创建一个QObject对象时,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是 parent,也就是父对象指针。
这相当于,在创建QObject对象时,可以提供一个其父对象,我们创建的这个QObject对象会自动添加到其父对象的children()列表。
n 当父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这里的父对象并不是继承意义上的父类!)

  • QWidget是能够在屏幕上显示的一切组件的父类。

QWidget继承自QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。事实就是如此,因为这些都是对话框的子组件。

  • 当然,我们也可以自己删除子对象,它们会自动从其父对象列表中删除。比如,当我们删除了一个工具栏时,其所在的主窗口会自动将该工具栏从其子对象列表中删除,并且自动调整屏幕显示。

image-20230619095633992

  • Qt 引入对象树的概念,在一定程度上解决了内存问题。
    • 当一个QObject对象在堆上创建的时候,Qt 会同时为其创建一个对象树。不过,对象树中对象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。
    • 任何对象树中的 QObject对象 delete 的时候,如果这个对象有 parent,则自动将其从 parent 的children()列表中删除;如果有孩子,则自动 delete 每一个孩子。Qt 保证没有QObject会被 delete 两次,这是由析构顺序决定的。如果QObject在栈上创建,Qt 保持同样的行为。正常情况下,这也不会发生什么问题。
    • 作为父组件的 window 和作为子组件的 quit 都是QObject的子类(事实上,它们都是QWidget的子类,而QWidget是QObject的子类)。这段代码是正确的,quit 的析构函数不会被调用两次,因为标准 C++要求,局部对象的析构顺序应该按照其创建顺序的相反过程。因此,这段代码在超出作用域时,会先调用quit 的析构函数,将其从父对象 window 的子对象列表中删除,然后才会再调用 window 的析构函数。
    • 在 Qt 中,尽量在构造的时候就指定 parent 对象,并且大胆在堆上创建。
2.8 Qt窗口坐标体系

坐标体系:
以左上角为原点(0,0),X向右增加,Y向下增加。

image-20230619095748503

3 信号与槽机制

3.1 信号与槽

信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。

image-20230619100459070

3.2 系统自带的信号与槽

connect()函数最常用的一般形式:connect(sender, signal, receiver, slot);
参数解释:

sender:发出信号的对象
signal:发送对象发出的信号
receiver:接收信号的对象
slot:接收对象在接收到信号之后所需要调用的函数(槽函数)

3.3 常用的信号

那么系统自带的信号和槽通常如何查找呢,这个就需要利用帮助文档了,在帮助文档中比如我们上面的按钮的点击信号,在帮助文档中输入QPushButton,首先我们可以在Contents中寻找关键字 signals,信号的意思,但是我们发现并没有找到,这时候我们应该想到也许这个信号的被父类继承下来的,因此我们去他的父类QAbstractButton中就可以找到该关键字,点击signals索引到系统自带的信号有如下几个

image-20230619101434174

3.4 自定义槽函数
#ifndef WIDGET_H
#define WIDGET_H
#include <QDebug>
#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
public slots: // 添加槽函数
    void print();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H


#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>

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

3.5 自定义信号

image-20230619164419572

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

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

image-20230619221022227

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](parameters) 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

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

4. QMainWindow

4.1 介绍

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

image-20230621000022651

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

  • 创建菜单栏,通过QMainWindow 类的menubar()函数获取主窗口菜单栏指针
//创建菜单栏:
#include <QMenuBar>
QMenuBar --> QMenuBar(QWidget *parent = Q_NULLPTR)
//添加菜单栏:
QMainWindow --> void setMenuBar(QMenuBar *menuBar)

  • 创建菜单,调用QMenu 的成员函数addMenu 来添加菜单
//创建菜单:
#include <QMenu>
QMenu --> QMenu(const QString &title, QWidget *parent = Q_NULLPTR)
//添加菜单:
MenuBar --> QAction *addMenu(QMenu *menu)

  • 创建菜单项,调用QMenu 的成员函数addAction 来添加菜单项
//创建菜单项:
#include <QAction>
QAction --> QAction(const QString &text, QObject *parent = nullptr)
//添加菜单项:
QMenu --> addAction(const QAction *action)

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

#include "mainwindow.h"
#include <QMenuBar> //菜单栏
#include <QMenu> //菜单
#include <QAction> //菜单项
#include <QDebug>
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

4.2 工具栏

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

//创建工具栏:
#include <QToolBar>
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

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 按钮。

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

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

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

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

指针赋给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 按钮。

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
[外链图片转存中…(img-8ySoGh91-1715847289046)]
[外链图片转存中…(img-ALjg6xqo-1715847289047)]

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

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

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值