Qt Creator 帮助我们在 HelloWorld 项目文件夹下生成了四个文件:main.cpp,mainwindow.cpp,mainwindow.h 和 HelloWorld.pro。pro 文件就是 Qt 工程文件(project file),由 qmake 处理,生成 make 程序所需要的 makefile;main.cpp 里面就是一个main函数,作为应用程序的入口函数;其他两个文件就是先前我们曾经指定的文件名的文件。所以我们写文件要写在main.cpp中。
#include <QApplication>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QLabel label("Hello, world");
label.show();
return app.exec();
}
点击 Qt Creater 左侧下面的绿色三角按钮即可运行(这里一共有三个按钮,从上到下分别是“运行”、“调试”和“构建”)。如果没有错误的话,就会看到运行结果:
前两行是 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 <QApplication>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QLabel *label = new QLabel("Hello, world");
label->show();
return app.exec();
}
这个程序就是不对的,原因:
首先,按照标准 C++ 来看这段程序。这里存在着内存泄露。当 exec() 退出时(也就是事件循环结束的时候。窗口关闭,事件循环就会结束),label 是没办法 delete 的。这就造成了内存泄露。当然,由于程序结束,操作系统会负责回收内存,所以这个问题不会很严重。即便你这样修改了代码再运行,也不会有任何错误。
严重的是,label 是建立在堆上的,app 是建立在栈上的。这意味着,label 会在 app 之后析构。也就是说,label 的生命周期长于 app 的生命周期。这可是 Qt 编程的大忌。因为在 Qt 中,所有的 QPaintDevice 必须要在有 QApplication 实例的情况下创建和使用。大家好奇的话,可以提一句,QLabel 继承自 QWidget,QWidget 则是 QPaintDevice 的子类。之所以上面的代码不会有问题,是因为 app 退出时,label 已经关闭,这样的话,label 的所有 QPaintDevice 一般都不会被访问到了。但是,如果我们的程序,在 app 退出时,组件却没有关闭,这就会造成程序崩溃。