一、通过图形化方式创建helloworld

首先我们创建好一个hello world项目,之后我们看到右上角红色框出生成了几个文件。双击最后一个文件(widget.ui)

我们会进入到以上的界面,我们看到下下边Label这个字样,将其拖入到中间的框框处。

双击输入我们需要打印的"hello world",之后我们点击右下角的运行符号就可以直接运行了。
我们可以看到Qt Designer右上角通过树形结构显示出了当前界面上有哪些控件
(上面为啥会有两个呢?是因为之前自己就试着弄了一遍)

之后我们返回到原来的页面发现ui文件中就会多出这样的一段代码

二、通过代码创建helloworld
我们再建立一个新的项目。

点击widget.cpp这个文件我们会看到这样的代码。一般通过代码来构建界面的时候,通常会把构造界面的代码放到Widget/MainWindow的构造函数中。

在上述代码的第一个红框我们包含头文件,但是我们看下面的图片,我们在包含头文件的时候,会出现两个提示。这两个提示分别是什么含义呢?下边这个全是小写的头文件其实就是在上古时期Qt的头文件包含风格。1998年之后C++标准成立了,C++98标准规定了包含头文件统一使用#include< cstdio >代替原有的#include< stdio.h >,所以Qt就响应号召,才有了上者这种写法。

再往下看,我们发现一个很奇怪的东西就是为什么要有这个this呢?这是什么东西,其实它是给当前label对象指定一个"父对象",后续我们会讲到对象树这个概念。其实也就是指向,下面一张图片中,main.cpp文件中我红色框框对象。


我们往下看最后这个行代码,其实意思就是设置控件中,要显示的文本,那么我们是不是很疑问,这个不是能用C++吗?为啥不直接std::cout<<std::endl?其实这个就要追溯到历史原因了,Qt诞生于1991年,那时候C++还没有形成标准,C++更没有"标准库"这样的改变了。当时我们是如何表示一个字符串的?是用C风格字符串也就是\0,也可以用C++的string,但是当时的string并不是很好用。这时候Qt就想着为了让自己的开发变得更加顺畅,就自己造了"轮子"(搞了一系列的基础类来支持Qt开发),但是很多年后,上述这些容器等内容已经打磨得很好了,形成了C++标准,但是Qt自己包装好的容器也不可能删掉,所以也就只能和现有的标准库中的容器类共存了。

上述将了那么多,我们运行一下程序,是否会出现helloworld这个字样呢?

上述的运行结果我们就可以看见,它运行成功,但是我们有没有发现它出现的位置和我们第一个helloworld位置不同呢?通过代码创建QLabel默认是在左上角,但是如果想放在别的地方也是可以的。
内存泄露问题
但是我们有没有发现一个很重要的问题?为什么我们上述new了之后,不需要delete?这样内存不是会泄露吗?
上述代码,在Qt中不会产生内存泄露。label对象会合适的时候被析构释放,虽然我们没有主动写,但是确实能释放。之所以能够把对象释放掉主要原因就是我们把这个对象挂到了对象树上。
前端开发(网页开发)也涉及到了类似对象树,本质上也就是一个树形结构(N叉树),通过树形结构把界面上的各种元素组织起来。所以Qt也搞了一个对象树,也是一个N叉树,把界面的各种元素组织起来。

使用对象树,把这些内容组织起来,最主要的目的是为了能够在合适的时机(窗口关闭/销毁)把这些对象统一释放。

上边使用new创建,其实是在堆上创建的方式,也就是下图这个

下边这个就是在栈上创建的方式,我们再看下边的那张图,就会发现什么都没有。此时的label对象随着构造函数的结束就销毁了。


下边我们写个代码来验证,内存是否会泄露。
我们再创建一个新的项目,同时在里边新建一个文件mylabel.cpp这个文件


这里创建自定义的类的主要目的就是自定义一个析构函数,在析构函数中完成打印,方便我们看到最终的结果。

我们创建一个析构函数。其中我们看到一个陌生的东西,qDebug()这是什么呢?其实这个是一个Qt提供的工具,借助这个就可以完成打印日志的工作,很好的处理字符串编码。其实它是一个宏封装了QDebug对象,直接使用qDebug()可以当做cout来使用。

正常运行得到结果。我们将运行框关闭,就得到我们析构函数打印的字段。这里也就证明了,当窗口关闭的时候会自动释放。

三、使用输入框实现helloworld
创建一个新的文件,点击ui文件,将LineEdit拖进中间的框中。
单行编辑框:QLineEdit
多行编辑框:QTextEdit

我们修改右侧text在编辑框中也会跟着修改

运行结果如下:

下边新建一个项目,我们使用纯代码的方式来实现上述功能:

四、使用按钮实现helloworld
通过图形化界面生成helloworld
创建一个新的文件,双击ui文件,找到Push Button

运行程序:

其实上述关联了一个Qt很重要的内容就是信号槽机制,后续会展开讲解。
其实本质就是给用户点击操作,关联上一个处理函数,当用户点击的时候就会执行这个处理函数。
其中我们会使用一个connect函数,这个我们这linux网络部分也见到过,不过这里的connect和TCP的建立连接操作没有任何关系!
Qt中的connect是QObject这个类提供的静态函数,这个函数的作用就是"连接信号"和"槽"。

第一个参数,访问到ui文件中创建的控件。在Qt Designer中创建一个控件的时候,此时就会给这个控件分配一个objectName属性。这个属性的值,要求是在界面中是唯一的,不能跟别人重复。
qmake在预处理.ui文件的时候,就会根据这里的objeName生成对应的C++代码。C++代码中该QPushButton对象的变量名就是这里的objextName。

通过纯代码的方式形成helloworld

如上我们建立一个按钮,并实现相关的跳转功能,但是我们发现实现该功能的时候,为啥会出现报错呢?其实就是myButton是在构造函数中的一个局部变量,那我们该怎么样才能访问呢?很简单,看下图:

将其在widget.h文件中声明,但是一定要记住包含头文件。

如上我们就完成了该功能的实现。
总结
对于通过图形化界面的方式实现按钮版的hello world: 此时按钮对象,不需要我们new,new对象的操作已经是被Qt自动生成了,而且这个按钮对象,已经作为ui对象里的一个成员变量了,也无需作为Widget成员。
对于纯代码方式实现按钮版hello world: 对于纯代码版本按钮对象就是我们自己new的,为了保证其他函数中能够访问到这个变量,就需要把按钮对象设定为Widget类的成员变量。
所以在实际开发中是通过代码的方式构造界面为主还是通过图形化界面的方式为主呢?
这两种都很重要
如果你当前程序界面,界面内容比较固定,此时就会以图形化界面的方式构造界面
如果你当前的程序界面,经常要动态变化,此时就会以代码的方式构造界面
