【初识Qt】
Application是应用程序,Application左边对应的是各种各样的项目模版,是点击Qt Widgets Application是图形化界面程序(图形化界面GUI)的项目模版,Qt Console Application如果需要用Qt写一个控制台程序(控制台界面PUI)就选该项目模版。
Qt Quick是Qt新搞出来的开发GUI程序的方式,传统的开发GUI程序的方式是Qt Widget,接下来学习的是Qt Widget这种方式,Qt Quick是比较新的方式,目前还没有普及。
接下来就需要填写项目名称和保存项目的路径
构建系统,Qt中代码编译流程是,使用内部的工具(也就是元代码)基于你写的C++代码生成一些其他的C++代码,再编译最后生成的C++代码。
有三种构建工具,Qbt是新一代的构建工具,但是由于使用的人很少,官方后来不再维护了,所以经常使用的还是qmake工具。
我们创建好项目之后,会自动生成一些代码,这些代码就包含一个类,如下图所示,这里选择的是自动生成的类的父类。这些父类是Qt内部已经写好的,像这种Qt内部写好的类的类名都是以Q开头。
这里的一些具体细节后面会专门讨论,当前阶段我们就选择QWidget,这个是最简单的方式,刚开始入门我们就选择最简单的方式。
如果勾选了Cenerate form这个选项,就会自动生成一个widget.ui这样的文件
一下是创建好的项目中会生成一些代码
- QApplication a(argc, argv);这行代码是创建一个QApplication对象,编写一个Qt的图像化界面程序,必须要有QApplication对象,我们后续写的代码很少操作很少直接操作这个QApplication对象。
- Widget w;在创建项目时选择了名为Widget的类,Qt Creator就会自动生成Widget w;的代码,是创建一个控件对象,.show方法是让控件显示出来,.hide方法是让控件隐藏起来,这两种方法是由父类QWidget来提供的。
- a.exec();表示让程序执行起来。
- Q_OBJECT是Qt内置的宏,在预处理时期会被替换成一大堆代码
- Widget(QWidget *parent = nullptr);构造函数,在Qt中有一个对象数的机制,构造时传入父节点指针,在对象创建好之后将该对象挂到对象树指定节点下。
.ui文件
Qt中使用.ui文件是用来描述程序运行后是怎么样的界面,根据xml所描述的内容生成C++代码,C++代码经编译后运行出来出来的结果就是和xml格式的内容所描述的界面是一样的。
.ui文件内容是xml格式的内容,xml和html一样,都是通过标签来表示数据,但是不同的是html中的标签对应的含义是固定的,xml中程序员可以自己创建标签,具体什么含义由自己来定,这里所看到的标签都是由开发Qt的大佬们一定的
.pro Qt项目的工程文件,是qmake工具构建时的重要依据,作用类似于Linux中的Makefile文件
在界面上显示出字符串有两种实现方式
- 通过图形化的方式创建出控件,显示出内容
label称为“标签”是用来能够在界面上显示字符串内容的控件
在设计中推拽的Label控件,会在.ui文件中生成如下一段代码
qmake会在编译项目时,基于.ui文件内容生成出C++代码
根据.ui文件生成的C++代码
- 通过编写代码方式,在界面上创建控件,显示出内容
一般将构件界面的代码写在类中的构造函数中
显示构造QString(“hello world”);
通过代码创建的QLabel默认显示在左上角
上述代码中没有包含QString对应的头文件,是因为QString对应的头文件在Qt内置的其他类中的头文件会被包含,上一般不需要显示包含,述代码中的头文件包含了QString对应的头文件。
Qt诞生于1991年,在当时表示一个字符串,有两种方式,一种是C风格的字符串,以/0结尾的方式,另一种是C++的string,在当时这两种方式写程序时相对不是太好用,Qt为了能够自己开发顺畅,自己再造了一套轮子写了一些基础类,来支持Qt的开发例如,字符串QString、链表QList、动态数组QVector。在当时C++没有形成标准,所以也就没有标准库,但是多年后C++有了标准库,Qt不可能将自己引入的容器类删掉,也就只能兼容C++标准库中现有的容器类。在Qt开发中使用C++标准库中的容器类和Qt自己的容器类都是可以的,但有一点Qt原生API中,涉及到的接口,用的都是Qt自己的容器类。QString使用起来要比string更方便一些,因为QString内部已经对字符编码做了处理,不会出现乱码的问题。
是否会造成内存泄漏的问题
对于内存泄漏和文件描述泄露这样类似的问题是挺严重的,因为这类问题不容易第一时间发现。
在上述代码中只动态开辟了对象,但并没手动去释放,这样不就造成了内存泄漏的问题吗?
上述代码在Qt中不会造成内存泄露的问题,label对象会在关闭界面后会自动释放,原因是因为该对象被挂在了对象树上,对象树本质是一个N叉树,通过树形结构将界面上所涉及的控件对象组织在了一起
使用对象树最主要的目的是为了能够在合适的时机将这些对象统一释放,也就是在关闭窗口时统一释放。上述创建QLabel对象要动态开辟目的是为了把这个对象的生命周期交给对象树来统一管理。
创建的对象是在栈上
- 没有显示出hello world,在构造函数结束时label对象就被销毁了。
验证当关闭界面口时会对象树会统一释放控件对象
由于QLabel类中析构无法看到效果,自定义一个类,然后继承QLabel类,在自定义类中的析构函数重打印出“label对象已释放”
创建成功会对出来两个文件
在Qt Creator中F4能够在头文件和对应的.cpp文件自由切换
自定义的MyLabel类继承QLabel类,所谓的继承就是在原有功能不变的基础上扩展出一个析构函数
运行结果
关闭窗口
有日志结果,说明关闭界面窗口后即使没有手动释放,由于label对象被挂到了对象树上,label对象也会自动被释放。
但是看到日志结果和我们想象中的不一样,这是出现了乱码的问题,出现乱码只有一个原因,编码方式不匹配。
中文一共有4K多个常用的汉字,算上生僻字一共有6W多个汉字,在计算机中存储的是二进制,对于汉字和ASCII码表中一样,一个汉字对应一个正整数,表示字符集的汉字有很多种,不同的字符集中,表示同一个汉字对应的数字不同。目前表示汉字字符集最主要有两种方式。
- GBK,主要应用于我们中国大陆,使用2个字节来表示一个汉字,在Windows系统中简体中文版默认使用的字符集就是GBK。
- UTF-8/uft8,使用的是变长编码的方式,表示一个符号使用的字节数有变化,字节数在2~4之间。
UTF-8编码方式一个汉字一般占3个字节,在Linux中用的就是utf8编码方式
查看具体的汉字utf8或者gbk编码是多少
在线工具:查看字符编码
由于"hello world"这个字符串是包含字mylabel.cpp文件中的,该字符串的编码方式和文件的编码方式是一致的
查看该.cpp文件的编码方式
用记事本打开
记事本打开之后另存为
弹出的对话框中显示的就是该文件的编码方式
上面出现乱码的现象,说明Qt Creator中内置的终端不是utf8来显示字符串。统一编码方式,要么让更改文件中的编码方式,要么更改Qt Creator中的编码方式。更改该种终端的编码方式不容易,并且更改后容易出现很多的问题。
注:编码中文主流的是utf8,utf8能够编码世界上各种语言文字。
解决这里乱码的方式:Qt中的QString类,打印工具qDebug能够自动处理字符串编码不一致的问题。
QDebug是一个类,qDebug()是一个宏,内部封装了QDebug类的对象,将其当做cout来使用。
后续再Qt中,如果想通过打印日志的方式,输出一些调试信息,优先使用qDebug,虽然使用cout也行,但是cout对于编码的处理不太好,在Windows上容易出现乱码,如果在Linux上使用Qt Creator是没有问题的。
使用qDebug还有一个好处,对于打印的调试日志,是可以统一关闭的,调试日志是在开发阶段打印的,如果程序发布给用户,是不能让用户看到这些日志信息的,因此需要在发布程序的时候统一将qDebug统一进行关闭。
接下来我们在空白窗口中显示hello world程序
接下来先通过图形化界面的方式,我们显示hello world可以使用很多种控件来完成,
Display Widgets这下面的控件就是用来显示的,我们先使用最简单的方式来完成,
该控件是一个普通的按钮,可以进行点击,但是目前发现点击之后没有什么反应,那怎么才能让点击之后有反应呢?这里就需要引入一个机制,信号槽,这里只是初步简单的使用,后面详细进行学习,信号槽本质上是给按钮的点击操作关联上一个处理函数,当用户点击的时候,就会执行这个处理函数。
这里就需要引入一个函数,connect(),Qt中的Connect是QObject这个类提供的静态函数,这个函数的作用就是连接信号和槽。
qmake在于处理.ui文件的时候,会根据这里的objectName生成对应的C++代码,在ui_widget.h文件中Ui_Widget有一个名为mybutton成员变量,ui->mybutton这个语句含义就是访问ui界面文件中的mybutton这个成员变量。
第一个参数:由哪个对象发出信号
第二个参数:发出的信号
第三个参数:需要关联槽函数,关联到哪个对象的槽函数上
第四个参数:具体的槽函数
我们来看这个函数的含义,ui->mybutton->text()先来获取ui界面文件中mybutton这个控件的内容,ui->mybutton->setText(“hello qt”)设置ui界面文件中mybutton的内容为"hello world"。
最终实现的效果就是点击按钮就会实现空间中的内容进行来回切换。(当点击这个按钮,就会触发&QPushButton::clicked这个信号,由于已将这个信号和this对象中函数进行了关联,所以就会执行this指针中的槽函数)
上面是图形化界面的基于按钮实现的hello world,接下来使用纯代码的方式来实现上面的效果
我们已经使用了两种方式来实现,写了对用的代码。对于纯代码版本,按钮对象是咱们自己new的,为了保证其他函数中能够访问到这个变量,就需要把按钮对象设定为Widget类的成员变量。对于图形化界面的版本,不需要咱们自己new,new对象的操作已经是被Qt自动生成了,而且这个按钮对象,已经作为ui对象里的一个成员变量了,也无须作为Widget的成员。
那在实际开发中,到底是以代码的方式构造界面为主,还是通过图形化界面的方式为主?
如果你当前程序界面,界面内容是比较固定的,此时就会以图形化的方式来构造界面,但是如果你的程序界面,经常动态变化,此时就会以代码的方式来构造界面,在实现的过程中哪种方式方便就使用哪种方式,而且这两种方式也可以配合使用,先通过图形化界面的方式将大体的框架搭建好,然后通过代码的方式填充框架中的细节内容。
Qt中的命名规范(在实际开发中命名规则以公司要求为主)
Qt中的常用快捷键
- 注释:ctrl+/
- 运行:ctrl+r
- 编译:ctrl+b
- 字体缩放:ctrl+鼠标滑轮
- 查找:ctrl+f
- 帮助文档:F1
- 自动对齐:ctrl+i
- 同名之间的.h和.cpp的切换:F4
- 生成函数声明的对应定义:alt+enter
- 整行移动:ctrl + shift + ⬆/⬇
在实际开发过程中一定要有查询文档的意识
1、光标放到要查询的类名/方法名上, 直接按 F1
2、Qt Creator 左侧边栏中直接用鼠标单击 “帮助” 按钮:
点击 “帮助” 之后,出现如下图示界面:
3、找到 Qt Creator 的安装路径,在 “bin” 文件夹下找到 assistant.exe,双击打开;
使用示例
1、新建项目,在新建的项目中使用 Qt 中的 “QpushButton” 控件。
2、打开帮助手册,在 “索引” 里面输入 “QpushButton”;
Qt中窗口坐标体系
move中移动的单位是像素,像素的本质就是有小亮点的和小灯泡来组成
给button移动位置,当然也可以给Widget,也就是窗口来移动位置