当前位置: 首页 > article >正文

Qt之hello world

目录

图形化的方式

使用QLabel

使用编辑框

使用按钮

纯代码的方式

使用QLabel

使用编辑框

使用按钮

关于对象树

观察现象

Qt的常用知识

快捷键

使用帮助文档

Qt 窗口体系


我们最开始学习语言时,第一个接触的知识就是输出字符串 "hello world" 吧,所以在学习Qt时,也学习一下,如何实现 hello world

两种方式实现 hello world:
①通过图形化的方式,在界面上创建出一个控件,显示 hello world
②通过纯代码的方式,通过编写代码,在界面上创建控件,显示 hello world

如果你当前程序界面内容是比较固定的,此时就会以图形化的方式来构造界面
但是如果你的程序界面经常要动态变化,此时就会以代码的方式来构造界面

这两种方式,哪种方便就用哪种,而且这两种方式也可以配合使用


图形化的方式

使用QLabel

在按照上篇博客所讲的,使用 Qt Creator 创建一个Qt项目后,双击右边的 widget.ui

就出现了图形化的界面设计器,可以进行窗口界面内容的编辑了

我们可以使用左侧栏中的一个简单的部件 Label 来完成

这时拖动这个Label到中间的界面,输入 hello world 即可显示出来:

此时在右上角处,通过树形结构,显示出了当前界面上都有哪些控件

刚才往界面上拖拽了一个 QLabel 控件此时, ui 文件的 xml 中就会多出来这一段代码:

进一步的 qmake 就会在编译项目的时候,基于这个内容生成一段 C++ 代码,通过这个 C++ 代码构建出界面内容了,是自动完成的

点击三角运行后,就能显示出 hello world 了:

此时打开与该项目的同级目录的文件,里面的 ui_widget.h 就是 qmake 根据 xml 的内容,生成的代码:

打开 ui_widget.h 后,能看到自动生成的代码:


使用编辑框

QLabel只能显示一个文本,无法做更多的交互性的工作

编辑框有两种:
①单行编辑框:QLineEdit
②多行编辑框:QTextEdit

下面使用单行编辑框,同样打开 widget.ui,点击左侧栏中的 Line Edit:

也将 Line Edit 拖到窗口上,并输入 hello world 文本:

这里的 hello world 也可以通过右侧的属性编辑区进行修改,下面是属于 Line Edit 的属性

想改变也可以点击 text 后面的框,输入进行改变:

并且在运行出来的窗口中,也可以进行输入文本:


使用按钮

继续打开 widget.ui 文件,点击左侧栏中的 Push Button:

继续将 Push Button 拖动到界面上去,输入 hello world:

点击运行,出现一个可以点击的按钮:

此处是可以点击的,但是没有反应,这个按钮有一个属性 objectName,叫做 pushButton,所以下面可以通过 ui->pushButton 获取到这个对象


这里就可以简单引入 Qt 中的信号槽的概念,后面会具体讲解
本质就是给按钮的点击操作,关联上一个处理函数当用户点击的时候,就会执行这个处理函数

下面就在 widget.cpp 中的构造函数中,使用connect函数
Qt 中的 connect 是 QObject 这个类提供的静态函数,这个函数的作用就是连接 信号和槽
这里的 connect函数 和 TCP 的建立连接操作没有任何关系

ui->pushButton 就表示从 ui 文件中访问到了 pushButton
QPushButton::clicked 就表示我们点击按钮时就会自动触发这个信号
this表示指定关联到 this 的槽函数上
&Widget::handleClick表示处理点击操作的函数

由于最后一个传入的 handleClick 函数还没有实现,所以现在实现一下,先在 widget.h 中声明:

再在 widget.cpp 中定义,实现了点击按钮后,可以 hello world 和 hello qt 来回切换:
下面的 text()函数 是获取文本的函数

此时运行程序:

点击一下按钮,变为:

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

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


纯代码的方式

使用QLabel

一般通过代码来构造界面的时候,通常会把构造界面的代码放到 Widget/MainWindow 的构造函数中,构造函数在 widget.cpp 中定义 

此时就可以 new 一个 Qlabel 对象:

Qt 中,每个类都有一个对应同名的头文件,如果用不了就显示包含一下头文件即可:

出现上述报错,就包含对应的头文件,与类同名:

在创建 label 对象时,可以选择像上面的在堆上创建,也可以选择在栈上创建,但是更推荐在堆上创建,具体原因在后面的对象树章节说明

new 对象时,最好传递一个参数 this
也就是给当前这个 label 对象,指定一个 父对象 this,这里的 this 就指向的当前的构造函数所对应的对象,也就是main函数中创建的 Widget 对象

接着就需要使用 setText 方法:

可以看到 setText 方法的参数是 QString,而不是 C++ 中的 std::string,是因为 Qt 是 1991年 诞生的,而 C++ 最早的标准也是 C++98了,即1998年产生的,在1991年,C风格字符串和C++的string都不太好用,所以Qt 为了让自己的开发能变的顺畅,就自己发明了一套轮子,搞了一系列的基础类,来支持 Qt 的开发

例如:
QString、QVector、QList、QMap等等

其中 QString 内部已经对于字符编码做了处理,不会出现乱码的问题
而 std:string,就啥都没干

所以直接传入 hello world即可:

在 QString 中也提供了 C风格字符串 作为参数的构造函数
不显式构造 QString,上述代码中的 C风格字符串 也会隐式构造成 QString 对象
并且 QString 对应的头文件,已经被很多 Qt 内置的其他类给间接包含了,因此一般不需要显式包含 QString 头文件

此时运行程序,如下所示:

通过代码创建 QLabel 默认是在左上角,如果想放到其他位置也是可以的(后续会讲)


使用编辑框

同样在 widget.cpp 的构造函数中添加对象:

此时运行程序:

效果和刚刚的图形化的方式是一样的,区别就是文本的位置在左上角


使用按钮

在 widget.cpp 中编写:

初步思路是上述代码,但是由于接下来实现 handleClick 函数时,无法获取到这里的局部变量 myButton,所以将 myButton 设置为成员变量:

widget.cpp 变为:

同样能够完成和图形化的方式一样的效果

点击变为:


关于对象树

这个代码,new 了对象之后,为什么最后没有 delete 呢,不 delete 不就出现内存泄漏了吗??

结论是:上述代码,在 Qt 中不会产生内存泄露,label 对象会合适的时候被析构释放
之所以能够把对象释放掉,主要是因为把这个对象是挂到了对象树上,也就是上述代码中创建对象时传入了this指针,指明了 父对象

Qt 中也是类似网页开发的对象数(DOM),也是搞了一个对象树,也是 N 叉树,把界面上的各种元素组织起来了,使用对象树把这些内容组织起来,最主要的目的,就是为了能够在合适的时机(也就是窗口关闭的时候),把这些对象统一进行释放

所以上述代码通过 new 的方式创建对象,也就是为了把这个对象的生命周期,交给 Qt 的对象树来统一管理

如果是在栈上创建的,运行时就不会看到 hello world,因为创建对象的代码是构造函数中实现的,当执行完构造函数后,该对象就会销毁,所以不会看到这个字符串


观察现象

下面创建一个 MyLabel 类,观察不手动释放 new 的对象,是否会自动释放

主要思路就是:
创建自定义的类,自定义析构函数,在析构函数中加上日志信息,观察关闭窗口后,在结果中会不会出现打印的日志

首先创建一个 MyLabel 的头文件和源文件:

选择C++,C++ Class:

接着指定我们要创建的类名为 MyLabel,下面的 Base Class 表示父类,手动输入父类为:QLabel

此时点击完成,就成功添加到项目中了:


此时点开 mylabel.h ,可以看到 Qt Creator 不认识 QLabel

所以需要手动包含,这也算是 Qt Creator 的其中一个体验不好的地方吧:
自动生成代码,但是却不自动生成所继承的父类的头文件,需要我们手动包含

下面我们改动一下MyLabel的构造函数,变为有参的构造函数,指定父元素,从而能够使得创建的 MyLabel 对象能够加入到对象树中

在 mylabel.cpp 中也做以修改:

接着需要手动创建析构函数

在 mylabel.cpp 中实现打印时,不能使用 C++ 中的 std::cout,因为可能编码方式不匹配,所以这里使用 qDebug 来打印日志,需要包含头文件 QDebug
下面所使用的 qDebug 是一个宏,后面直接跟上需要输出的字符串即可,会自动处理编码问题

此时 widget.cpp 中,创建一个 MyLabel 对象,注意需要包含 mylabel.h 头文件:

此时运行程序,出现 hello world:

再点开输出界面,关闭这个窗口后,输出如下:

可以看到我们的代码中是没有 delete 的,而程序自动调用了析构函数,从而验证了我们上面所说的结论


小结:

①认识 QLabel 类,能够在界面上显示字符串,通过 setText 来设置的(参数是 QString)

对象树,Qt 中通过对象树,来统一的释放界面的控件对象
Qt 还是推荐使用 new 的方式在堆上创建对象, 通过对象树,统一释放对象创建对象的时候,在构造函数中,指定父对象(此时才会挂到对象树上)
如果你的对象没有挂到对象树上,就必须要记得手动释放

③通过继承自 Qt 内置的类,就可以达到对现有控件进行功能扩展效果,Qt 内置的 QLabel,没法看到销毁过程的
为了看清楚,就创建类 MyLabel,继承自 QLabel,并重写了析构函数
在析构函数中,加上日志,可以直观的观察到对象释放的过程
也可以重写控件中的任何功能,不仅仅是析构函数,从而达到功能扩展目的

乱码问题和字符集
如果使用 cout 就可能出现乱码问题,而乱码问题就是编码方式不匹配导致的
汉字不同于英文字母,汉字总计 6万 多个,并且表示同一个汉字有不同的方式,也就是字符集是不同的,不同的字符集,表示同一个汉字,所使用的数字是不相同的

目前表示汉字的字符集主要有两种方式:GBK、UTF-8(utf8)
GBK:主要在中国使用,使用 2 个字节表示一个汉字,我们使用的Windows 简体中文版,它默认的字符集就是 GBK
UTF-8:变长编码,表示一个符号,使用的字节数有变化,一般是2 - 4字节,但是在 utf8 中,一个汉字,一般是 3 个字节

⑤在 Qt 中打印日志
作为调试信息,使用 cout 固然可以,但是并不是上策 (因为cout的字符编码处理的不好,也不方便统一进行关闭)
Qt 中推荐使用 qDebug() 完成日志的打印,它可以自动进行编码处理的操作
并且使用 qDebug() 时,是可以通过编译开关统一关闭,cout则做不到这一点


Qt的常用知识

快捷键

注释:ctrl + /
运行:ctrl + R
编译:ctrl + B
字体缩放:ctrl + 鼠标滑轮
查找:ctrl + F
整行移动:ctrl + shift + ⬆/⬇
帮助文档:F1
自动对齐:ctrl + i
同名之间的 .h 和 .cpp 的切换:F4
生成函数声明的对应定义:alt + enter

使用帮助文档

方式一:光标放到要查询的类名/方法名上,直接按F1

方式二:Qt Creator 左侧边栏中直接用鼠标单击 "帮助" 按钮

方式三:Qt assistant 也是帮助文档


Qt 窗口体系

Qt 的坐标系是平面直角坐标系,也叫做笛卡尔坐标系

但是也与我们之前数学中的坐标系不同,如下所示:

①坐标系的原点 (0, 0) 就是 屏幕的左上角/窗口的左上角
②给 Qt 的某个控件,设置位置, 就需要指定坐标,对于这个控件来说,坐标系原点就是相对于父窗口/控件的

而 Widget 没有父元素,所以就是以桌面的左上角为原点设置的

所以我们就明白了,为什么上面使用纯代码的方式,创建出的按钮是在左上角的,默认情况下就是在 (0, 0)位置,也就是左上角的

运行可以看到是在左上角的:

可以使用 move函数 来设置位置,move中单位是像素:

运行程序可以看到:

也就是:

这里的像素其实我们的笔记本电脑中,显示设置-显示器分辨率中的 1920 × 1080,这两个数字的单位就是像素



http://www.kler.cn/news/365927.html

相关文章:

  • 批处理操作的优化
  • 【C++篇】栈的层叠与队列的流动:在 STL 的韵律中探寻数据结构的优雅之舞
  • 最新版本jdbcutils集成log4j做详细sql日志、自动释放连接...等
  • Python实现微博舆情分析的设计与实现
  • PostgreSQL用load语句加载插件
  • qt creator 转 visual stdio 项目调试
  • SpringBoot面试热题
  • 麒麟v10 arm64 部署 kubesphere 3.4 修改记录
  • C#与Sqlite数据库
  • 01. 初识C++
  • 钉钉录播抓取视频
  • UML 总结(基于《标准建模语言UML教程》)
  • HW支持-定时扫描局域网内所有设备MAC不在白名单则邮件提醒
  • winmm劫持详解
  • postman使用——在公司的项目落地回顾总结
  • 【计算机操作系统】课程 作业二 进程与线程 408考研
  • uniapp使用easyinput文本框显示输入的字数和限制的字数
  • WUP-MY-POS-PRINTER 旻佑热敏打印机票据打印uniapp插件使用说明
  • WebGL 3D基础
  • 常见Linux命令笔记
  • 【python爬虫】request发请求时需要携带cookies请求举例
  • 计算机网络:网络层 —— IPv4 协议的表示方法及其编址方法
  • 定位基站共线
  • 【卡尔曼滤波】观测模型包含输入的线性卡尔曼滤波
  • C++的汉诺塔
  • 【C语言教程】【嵌入式编程】(五)驱动开发实战(六)高级实践项目(七)附录