• 【QT】Hello World!


    💦创建项目

    • 创建新项目
      在这里插入图片描述
    • 选择项目位置
      在这里插入图片描述
    • 选择编译套件
      在这里插入图片描述
    • 选择创建类信息,后续点击完成即可
      在这里插入图片描述
    • 创建成功
      在这里插入图片描述

    💦项目组成

    可以看到,Qt Creator 帮助我们在 HelloWorld 项目文件夹下生成了四个文件:main.cpp,widget.cpp,widget.h 和 HelloWorld.pro。pro 文件就是 Qt 工程文件(project file),由 qmake 处理,生成 make 程序所需要的 makefile;其他两个文件就是先前我们曾经指定的文件名的文件。

    //HelloWorld.pro
    #-------------------------------------------------
    #
    # Project created by QtCreator 2022-08-05T08:08:15
    #
    #-------------------------------------------------
    
    # 默认参数
    QT       += core gui
    
    # QT版本大于4
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = HelloWorld //生成exe文件的名称
    # 项目生成(lib-建立一个库的makefile;vcapp-建立一个应用程序的VS项目文件;vclib-建立一个库的VS项目文件;subdirs-这是一个特殊的模板,它可以创建一个能够进入特定目录并且为一个项目文件生成马克file并且为它调用make的makefile)
    TEMPLATE = app
    
    # The following define makes your compiler emit warnings if you use
    # any feature of Qt which has been marked as deprecated (the exact warnings
    # depend on your compiler). Please consult the documentation of the
    # deprecated API in order to know how to port your code away from it.
    DEFINES += QT_DEPRECATED_WARNINGS
    
    # You can also make your code fail to compile if you use deprecated APIs.
    # In order to do so, uncomment the following line.
    # You can also select to disable deprecated APIs only up to a certain version of Qt.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    # 配置信息
    CONFIG += c++11
    # 源文件
    SOURCES += \
            main.cpp \
            widget.cpp
    # 头文件
    HEADERS += \
            widget.h
    
    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    其他两个文件就是先前我们曾经指定的文件名的文件。

    //widget.h 
    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include 
    
    class Widget : public QWidget //所有控件的基类,就是窗口
    {
        Q_OBJECT
    
    public:
        Widget(QWidget *parent = 0);
        ~Widget();
    };
    
    #endif // WIDGET_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    //widget.cpp
    #include "widget.h"
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
    {
    }
    
    Widget::~Widget()
    {
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    main.cpp 里面就是一个main函数,作为应用程序的入口函数;

    #include "widget.h"
    #include 
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);//QT框架的初始化
        Widget w;
        w.show();
    
        return a.exec();//作用是让程序循环不死,检测事件的发生
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • Qt系统提供的标准类名声明头文件没有.h后缀
    • Qt一个类对应一个头文件,类名就是头文件名
    • QApplication应用程序类
      管理图形用户界面应用程序的控制流和主要设置。
      是Qt的整个后台管理的命脉它包含主事件循环,在其中来自窗口系统和其它资源的所有事件处理和调度。它也处理应用程序的初始化和结束,并且提供对话管理。
      对于任何一个使用Qt的图形用户界面应用程序,都正好存在一个QApplication对象,而不论这个应用程序在同一时间内是不是有0、1、2或更多个窗口。
    • a.exec()
      程序进入消息循环,等待对用户输入进行响应。这里main()把控制权转交给QL,Qu完成事件外理工作,当应用程序退出的时候exee0的值就会返回。在 exec()中,Qi接受并处理用户和系统的事件并且把它们传递给适当的窗口部件。

    💦项目运行

    点击 Qt Creater 左侧下面的绿色三角按钮即可运行(这里一共有三个按钮,从上到下分别是“运行”、“调试”和“构建”)。如果没有错误的话,就会看到运行结果。
    通过右键点击,找到项目所在文件夹
    在这里插入图片描述
    此时显示项目文件夹中文件的类型有
    在这里插入图片描述
    打开编译文件夹
    在这里插入图片描述

    💦创建空项目

    • 新建一个空项目
      在这里插入图片描述

    • 会发现这个空项目只有一个pro文件,此时就可以手动新建编写文件
      在这里插入图片描述
      新建main.cpp
      在这里插入图片描述
      在这里插入图片描述

    • 添加主框架代码,会发现有报错如图1,这时选中QApplication按F1,打开帮助文档如图2,会发现在qmake中需要添加如图语句,而qmake的文件正是pro文件,所以在pro文件中添加即可,如图3。
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

    • 添加窗口QWidget,并显示(对于控件函数的使用可以选中类使用F1来查找)。控制台打印输出信息QDebug。

    #include 
    #include 
    #include 
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);//QT框架的初始化
        QWidget widget;
        widget.resize(400,300);//设置窗口大小
        widget.setWindowTitle("Hello World!");//设置窗口标题
        widget.show();
        qDebug()<<"Hello World!";
    
        return a.exec();//作用是让程序循环不死,检测事件的发生
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    在这里插入图片描述

    Tip:在栈和堆上创建对象的区别

    #include 
    #include 
    
    int main(int argc, char *argv[])
    {
       QApplication app(argc, argv);
    
       QLabel label("Hello, world");
       label.show();
    
       return app.exec();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    前两行是 C++ 的 include 语句,这里我们引入的是QApplication以及QLabel这两个类。main()函数中第一句是创建一个QApplication类的实例。对于 Qt 程序来说,main()函数一般以创建 application 对象(GUI 程序是QApplication,非 GUI 程序是QCoreApplication。QApplication实际上是QCoreApplication的子类。)开始,后面才是实际业务的代码。这个对象用于管理 Qt 程序的生命周期,开启事件循环,这一切都是必不可少的。在我们创建了QApplication对象之后,直接创建一个QLabel对象,构造函数赋值“Hello, world”,当然就是能够在QLabel上面显示这行文本。最后调用QLabel的show()函数将其显示出来。main()函数最后,调用app.exec(),开启事件循环。我们现在可以简单地将事件循环理解成一段无限循环。正因为如此,我们在栈上构建了QLabel对象,却能够一直显示在那里(试想,如果不是无限循环,main()函数立刻会退出,QLabel对象当然也就直接析构了)。
    如果在堆上创建对象呢

    #include 
    #include 
    
    int main(int argc, char *argv[])
    {
     QApplication app(argc, argv);
    
     QLabel *label = new QLabel("Hello, world");
     label->show();
    
     return app.exec();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    答案是,不建议这样做!
    首先,按照标准 C++ 来看这段程序。这里存在着内存泄露。当exec()退出时(也就是事件循环结束的时候。窗口关闭,事件循环就会结束),label 是没办法 delete 的。这就造成了内存泄露。当然,由于程序结束,操作系统会负责回收内存,所以这个问题不会很严重。即便你这样修改了代码再运行,也不会有任何错误。
    早期版本的 Qt 可能会有问题(详见本文最后带有删除线的部分,不过豆子也没有测试,只是看到有文章这样介绍),不过在新版本的 Qt 基本不存在问题。在新版本的 Qt 中,app.exec()的实现机制确定,当最后一个可视组件关闭之后,主事件循环(也就是app.exec())才会退出,main()函数结束(此时会销毁app)。这意味着,所有可视元素已经都关闭了,也就不存在后文提到的,QPaintDevice没有QApplication实例这种情况。另外,如果你是显式关闭了QApplication实例,例如调用了qApp->quit()之类的函数,QApplication的最后一个动作将会是关闭所有窗口。所以,即便在这种情况下,也不会出现类这种问题。由于是在main()函数中,当main()函数结束时,操作系统会回收进程所占用的资源,相当于没有内存泄露。不过,这里有一个潜在的问题:操作系统只会粗暴地释放掉所占内存,并不会调用对象的析构函数(这与调用delete运算符是不同的),所以,很有可能有些资源占用不会被“正确”释放。事实上,在最新版的 Sailfish OS 上面就有这样的代码:

    #include 
    
    int main(int argc, char *argv[])
    {
       QScopedPointer<QApplication> app(new QApplication(argc, argv));
       QScopedPointer<QQuickView> view(new QQuickView);
       view->setSource("/path/to/main.qml");
       ...
       return app->exec();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这段代码不仅在堆上创建组件实例,更是把QApplication本身创建在了堆上。不过,注意,它使用了智能指针,因此我们不需要考虑操作系统直接释放内存导致的资源占用的问题。
    当然,允许使用并不一定意味着我们建议这样使用。毕竟,这是种不好的用法(就像我们不推荐利用异常控制业务逻辑一样),因为存在内存泄露。而且对程序维护者也是不好的。所以,我们还是推荐在栈上创建组件。因为要靠人工管理new和delete的出错概率要远大于在栈上的自动控制。除此之外,在堆上和在栈上创建已经没有任何区别。
    如果你必须在堆上创建对象,不妨增加一句:

    label->setAttribute(Qt::WA_DeleteOnClose);//在窗口接受了关闭事件后,Qt会释放这个窗口所占用的资源,这样在关闭这个窗口时Qt能够自动回收该窗口所占用的资源,这样能够及时回收无效的资源,有用利于节约内存空间。
    
    • 1

    这点提示足够告诉程序维护者,你已经考虑到内存问题了。

  • 相关阅读:
    计算属性的学习
    windows上修改redis端口号
    springboot基于spring的宽带管理系统以及实现毕业设计源码250910
    基于SpringBoot的SSMP整合案例(开启日志与分页查询条件查询功能实现)
    ssm+vue+elementUI 高校志愿者服务招募网站-#毕业设计
    Allegro如何输出IDF文件操作指导
    golang数据库连接池参数设置
    网络编程概述及Http协议
    Java编程笔记25:TCP
    希望计算机专业同学都知道这些老师
  • 原文地址:https://blog.csdn.net/qq_36477513/article/details/126170159