通过代码创建helloworld

一般通过代码来构造界面的时候,通常会把构造界面的代码放到Widget/Mainwindow的构造函数中

显示没有这个类,所以要包含对应的头文件,在Qt中每个类都有一个对应同名的头文件。

上古时期,Qt一直用到是下面那种风格的头文件,1998年之后,C++标准成立了C++98标准。规定,包含头文件统一使用#include <cstdio> 代替原有的 #include <stdio.h>

label 意为"标签",其实就是用来显示内容的一个字符串控件

创建对象的时候可以在堆上或者在栈上创建

在构造label的时候记得给个参数this,那么这个this是什么意思呢?

之前提到过Qt中有一个重要的概念称为——对象树,其实就是一个普通的N叉树,换句话说他就是通过这种树形结构把我们这些控件对象组织到一起了(树的特点:每个节点都可以有n个字节点,但是只能有一个父节点),既然指定了它的父节点那么也就知道它在树的哪一个位置了。那么这个this指向的又是谁呢?就是widget类所构建的对象,就是main函数中的 Widget w;

设置控件中显示的文本是啥。那么这个QString是什么类型

Qt诞生于1991年,而那时候C++还没有形成标准,更没有"标准库"这样的概念了

当时,如何表示一个字符串可以使用两种方式:

C风格的字符串(\0结尾);也可以使用C++的string

但是当时这两种都不太好用(现在C的依然不好用)

所以Qt为了让自己的开发能变得顺畅,就自己发明了一套轮子——搞了一系列的基础类,来支持Qt的开发,包括但不限于:

字符串                QString

动态数组            QVector

链表                   QList

字典                   QMap

......

很多年之后,上述这些容器等内容,已经打磨的很好了,形成了C++标准

很显然,这些已经引入的Qt自己包装好的这些容器类,也不可能删了,那么就只能和现有标准库中的容器类共存了

因此,我们开发 Qt 代码的时候,如果需要用到上述容器类,可以使用标准库容器,也可以使用Qt 自己写的容器。

但是 Qt 的原生api中涉及到的接口用的都是 Qt 自己的这一套容器.

上边是显示的构建了一个QString对象,但是不这么写也是可以的,QString中也提供C风格字符串作为参数的构造函数。不显示构造QString,下面代码中C风格字符串也会隐式构造成QString对象

QString对应的头文件,已经被很多 Qt内置的其他类给间接包含了,一般就不用再引头文件了

此时我们就显示出了hello world,通过代码创建的QLabel默认是在左上角,如果想放到其他位置也是可以做到的,等后边在说。

对象树

这里new了之后不delete就直接运行,不是应该出现内存泄漏吗?

上述代码,在Qt中不会产生内存泄漏,label 对象会在合适的时候被析构释放(虽然没有手动写delete,但是确实能够释放)。

之所以能够把对象释放掉,主要是因为把这个对象挂到了对象树上。

通过这个树形结构,就把界面上要显示的这些控件对象都组织起来了

使用对象树,把这些内容组织起来,最主要的目的,就是为了能够在合适的时候,把这些对象统一释放。什么时候是合适的时候呢?——窗口被关闭/销毁

为什么要统一释放呢?

如果某个对象提前销毁,那么窗口界面的对应显示的控件不久没了吗

当我们的对象在栈上创建,并不能在窗口中显示出helloworld,此时的label对象在构造函数结束就销毁了(一瞬间就没了)。

新建文件来看一下具体是怎么销毁的

MyLabel这个类继承自QLabel

改一下构造

.cpp也要改

调用这个父类的构造函数,只有调用这个,才能让我们自己类的对象加入到 Qt 对象树中,而创建自定义的类,最主要的目的是自定义一个析构函数,在析构函数中完成打印,让我们能够看到最终的自动销毁

声明析构

小技巧:当我们写完一个函数的声明之后(光标选中析构函数)然后alt + enter 会出现

再按回车自动会帮我们添加定义

然后在析构中添加打印提示

在widget.cpp中

用我们自己的类创建对象,使用自己定义的MyLabel 代替原来的QLabel,所谓的"继承"本质上是扩展,保持原有功能的基础上,给对象扩展出一个析构函数,通过这个析构函数,打印一个自定义的日志,方便我们观察程序的运行效果。

程序成功运行

但是应用程序输出框中没有内容,这是因为界面窗口还没有关闭,窗口关闭了才会调用析构

日志有,说明析构函数是执行了的,虽然没有手动delete但是由于我们把MyLabel挂到了对象树上。此时窗口被销毁的时候,就会自动销毁对象树中所有的对象。美中不足的是,本该输出中文的地方是一串乱码。

乱码问题出现的原因有且只有一个(不局限于C++)——就是编码方式不匹配!

乱码问题

在计算机中,一个汉字占几个字节?

针对这个问题,如果回答的是一个具体的数字,那么就是错的。一个汉字占几个字节,有一个前提条件——当前中文编码使用的是哪种方式(字符集)

计算机中存的是二进制,英文字符用ASCII码表表示,规定每个字符,都有一个对应的数字来表示。只是表示英文,一个字节足够了,毕竟英文字母的数目十分有限。而中文的日常用字就有4k多个,算上各种不常用的生僻字的话得有6w多。

中文仍然使用一个大表格,给每个汉字分配一个整数即可。

具体这个表格是什么样子?

具体每个汉字都使用哪个数字表示?

这个事情就不一定了

字符集——表示汉字的字符集,其实是有很多种的。不同的字符集,表示同一个汉字,使用的数字不同。

目前,表示汉字的字符集,主要有两种方式:

1.GBK(中国大陆) 使用2个字节表示一个汉字

        Windows简体中文版,默认的字符集就是 GBK.

2.UTF-8 / utf8  变长编码,表示一个符号,使用的字节数有变化(2~4)

        但是在utf8中,一个汉字一般是3个字节.Linux中一般是utf8

这个字符串使用的编码方式是和当前 mylabel.cpp文件的编码的方式是一致的

怎么查看这个文件的编码方式呢?右键文件在explorer中显示

找到mylabel.cpp,右键此文件以记事本的方式打开,在记事本中另存为,这时就可以看到编码方式了

如果显示的UTF-8,那么这个文件就是UTF-8编码;

如果显示的是ANSI,说明这个文件是 GBK 编码

Qt Creator 内置的终端是用utf8的方式来显示字符串吗?——不一定

Qt 中有一个东西——QString是可以帮我们自动的处理编码方式的

不只是QString,Qt也提供了专门用来打印日志的工具,也能自动处理编码方式。

Qt提供了一个qDebug()工具,借助这个,就可以完成打印日志的过程,很好的处理了字符编码(不需要程序员关注了,内部帮我们处理好了)。

怎么去使用qDebug呢?和我们使用cout类似

注意使用时的大小写。QDebug是一个qt中的类,我们使用时不会直接使用这个类,而qDebug这个宏封装了QDebug对象,直接使用qDebug()就行了

这会儿打印的内容就正常了

使用qDebug还有一个好处——打印的调试日志,是可以统一进行关闭的。

输出的日志是开发阶段调试程序的时候使用的,如果你的程序发布给用户,肯定是不希望用户看见这些日志的。qDebug就可以通过一些编译开关,来实现一键式的关闭。

使用按钮创建hello world

双击widget.ui文件,在左边的控件列表中找到Push Button(普通按钮),一般使用按钮都用这个

直接把push button 拖到右边窗口中

在按钮框中输入hello world ,然后就可以点击左下角运行了

按钮一般点击后都有某种效果的,那么如何让按钮点击后有效果呢?

这就涉及到了信号槽机制,后面会详细介绍,此处先简单演示一下使用的方式

其实本质就是给按钮的点击操作关联上一个处理函数。当用户点击的时候就会执行这个处理函数。

connect函数

Linux网络编程中,也学习过一个函数,叫做connect。这个函数是用来给TCP建立连接的。写TCP客户端的时候,就需要先建立连接,然后才能读取数据。

Qt 中的这个connect 是 QObject这个类提供的静态函数,这个函数的作用就是"连接信号和槽"

和TCP的建立连接的操作没有任何关系。

这个函数共有4个参数:

参数1:谁发的信号——按钮发的

参数2:点击按钮触发的信号(一个函数指针)

参数3:关联到哪个对象的成员函数上(谁来处理这个信号)

参数4:函数(具体怎么处理)

访问form file(ui文件)中创建的控件

在Qt Designer中创建一个控件的时候,此时就会给这个控件分配一个 objectName属性,这个属性的值,要求是在界面中得是唯一的(不能和别人重复)

qmake在预处理.ui文件的时候,就会根据这里的 objectName 生成对应的C++代码,C++代码中该QPushButton对象的变量名字就是这里的objectName。

这个变量就是UI属性中的成员变量。

声明一下handleClick

定义处理函数

通过ui->pushButton这个操作获取到界面的按钮,为什么能够取得这个按钮,因为这个按钮有个属性叫objectName,这个属性叫pushButton,那么就可以用ui->的方式来获取按钮,ui是创建项目时qmake自动生成的

在ui_widget.h中,自动生成的代码里就会包含一个pushButton的成员变量,这个变量的名字,就是根据objectName的值来确定的

objectName中设置成什么值,生成的变量就是什么名字,就可以根据这个名字来获取到对应的控件的变量了。

Ui_Widget这个类,在底下又会生成一个类widget继承自Ui_Widget,新生成的类又在命名空间Ui中,所以widget.h中的类的成员变量所引用的命名空间中的Widget类的指针。

既然widget继承自Ui_Widget,那么ui就可以通过widget访问Ui_Widget中的内容了

变量名命名规范

类名:首字母大写,单词和单词之间首字母大写。

函数名及变量名:首字母小写,单词和单词之间首字母大写

Qt偏好驼峰命名法,这一点不像之前的蛇形命名法。

查询文档的方式

1.光标放到要查询的类名/方法名上,直接按F1

2.Qt Creator 左侧边栏直接用鼠标单击"帮助"按钮

3.打开Qt Assistant

认识 Qt 窗口坐标系

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

可以使用move这个函数来改变按钮的位置

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    myButton = new QPushButton(this);
    myButton->setText("hello world");
    myButton->move(400,300);

}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐