Qt——入门基础

news2024/11/25 16:49:21

目录

Qt入门第一个应用程序

main.cpp

widget.h

widget.cpp

widget.ui

.pro

Hello World程序

对象树

编辑框

按钮

 Qt 窗口坐标系


Qt入门第一个应用程序

main.cpp

        这就像一开始学语言时都会打印一个“Hello World”一样,我们先来看看创建好一个项目后,运行出来是什么样的。

        运行后就出现了一个简单的对话框,可以执行缩小、全屏、关闭等操作,这就不再是原来的黑框了,通过我们的不断学习就可以让这个对话框丰富起来。

        现在我们就来看一下这个代码都做了什么:

  • 首先就是main函数,有它的两个命令行参数:argc和argv。
  • 下面就是QApplication实例化的对象,并把命令行参数传入,编写Qt图形化界面程序一定要有这个对象
  • 下面还有一个Widget对象,这是在创建项目时选择的类名,并调用show方法,意思就是让控件显示出来,相对的还有一个hide方法,意思就是让控件隐藏

  • 最后就是返回了exec方法,表示让程序执行起来,但是这并不同于Linux的进程替换函数,这两个没有任何关系。

widget.h

        在项目中还有很多文件,不要着急,我们一个一个说。

        这个文件中放的就是widget类的声明。

  • 一开始的条件编译保证头文件只包含一次,但是更推荐使用#pragma once,这里就使用自动生成的就可以了。
  • 下面首先声明了命名空间Ui,我们创建项目时就定义的Widget类名,widget头文件和源文件
  • 原来我们没有怎么见过继承,这里我们就见到了,我们的Widget类就继承了QWidget父类,这个类是Qt SDK内置的,要想使用就要包含QWidget头文件。
  • Q_OBJECT宏,这个宏是Qt内置的,展开后是大量的代码,这是因为Qt中还有一个核心机制就是“信号 和 槽”,等我们后面说到的时候再谈,要想使用就要引入这个宏。
  • 构造函数中的参数:QWidget *parent = nullptr,的这也是Qt中的一个机制,叫做“对象树”,创建的Qt对象要挂到这个树上,要指明父节点,这也是后面再说。

widget.cpp

        这个文件中就是widget类中方法的实现。

  • 构造函数中还是和下面的文件有关系的,这到下面的时候再详细说,总之ui要把form file生成的界面和widget关联起来。
  • 析构函数就delete就可以了。

widget.ui

        在项目目录中有个Forms文件夹中有这个widget.ui文件,双击就会进入这个Qt Designer界面,这是一个图形化的界面编辑器,左边栏是Qt内置的控件,通过拖拽的方式就可以创建出具体的界面,右边是控件的属性,会影响控件具体的行为。

        此时返回编辑就可以看到这个文件中写的是什么。

        这个文件的格式就是xml格式,和html类似,都是使用成对的标签来表示数据,这些标签就是开发出Qt的程序员决定的,这就类似于网络中的自定义的应用层协议。

        这个文件就是Qt中描述程序界面的一个文件,之后qmake会调用相关的工具,根据这个xml文件生成对应的C++代码。

.pro

        这个文件就是Qt项目的工程文件,也是qmake工具构建时的重要依据。

  • 首先就是引入的Qt模块,这里只有core和gui。
  • CONFIG就是让编译器按照什么标准编译。
  • 关键的就是SOURCES、HEADS和FORMS,这些描述了当前项目中参与构建的文件。
  • qmake与.pro文件的作用就类似于makefile,只是Qt Creator把细节封装好了。

        当我们打开这个项目的目录时会发现除了项目目录, 还有一个build目录,这个目录名字也比较长,进入这个文件就会看到这些文件。

  • 这里有一个Makefile文件,这就是qmake自动自动生成的。
  • 还有一个ui_widget.h文件,这个文件就是widget.cpp文件中引入的头文件,这个文件就是.ui文件中xml生成的.h文件

  • 这就是widget.h文件中Widget类的成员变量的类型,这个变量的类型是Ui命名空间中继承了Ui_Widget类的一个类,虽然名字是一样的,但是不要弄混。
  • 在构造函数中也调用了这个类中的setupUi方法


Hello World程序

        没错,每学习一个新的语言我们都要写一个Hello World程序,实现的方式有两种:

  1. 通过图形化界面的方式,在界面上创建出一个控件来显示。
  2. 通过纯代码的方式,在界面上创建出一个控件来显示。

        我们先来使用第一种图形化界面的方式,当我们点击.ui文件时就会跳转到Qt Designer界面,左边的控件栏乡下就有一栏Display Widgets,这就是显示的控件。

        通过拖拽这个Label控件添加到界面中,双击编写文本,之后右侧通过树形结构显示出当前界面中都有哪些控件。

        在.ui中的xml文件中就会多出这段代码。

        当qmake编译项目的时候就会就这个内容生成一段C++代码,这段代码就在ui_widget.h文件中。

        通过这个代码就可以构建出界面内容,运行后就可以看到Hello World。

 

        之后我们再来使用第二种纯代码的方式,使用纯代码就要在Widget的构造函数中写。

        我们想要添加label标签,就是一个显示字符串的空间,在Qt中每一个控件都有对应的头文件。并且更推荐在堆上创建,在构造时,因为有对象树,所以可以给label对象传入一个父节点,而这个this就是main函数中创建的Widget对象

        下面就是编写label中的字符串,在Qt中支持两套string,分别是Qt自己开发的QString和C++标准的std::string,但是Qt中的原生API使用的都是QString,所以我们使用QString就可以了,而且QString和std::string之间的转换也是很方便的。

        这里我们写成了C风格的字符串也是可以的,它也会隐式类型转换成QString对象,运行后就可以看到了,只不过这里默认放到了左上角。

【注意】:这里使用new之后,要不要delete呢,我们都知道内存泄漏这种问题是很严重的,而且还不容易发现,那为什么没有写delete呢,那我们下面就来说一下。

对象树

        其实即使不写delete也不会造成内存泄漏,因为label对象会在合适的时候被析构,之所以能被释放就是因为对象被挂到了对象树上。

  • 当创建⼀个QObject对象时,其构造函数接收⼀个QObject指针作为参数,这个参数就是 parent,也就是⽗对象指针
  • 意思就是可以提供⼀个其⽗对象,我们创建的这个QObject对象会⾃动添加到其⽗对象的children()列表
  • 当⽗对象析构的时候,这个列表中的所有对象也会被析构
  • 要注意的是,这⾥的⽗对象并不是继承意义上的⽗类

  • 这样就可以通过树形结构把界面上要显示的控件对象组织起来,这就可以在合适的时机把这些对象统一释放,也就是在窗口关闭或销毁的时候
  • 如果提前释放了某个对象,那就不会在界面上显示出来了。
  • 通过new的方式把对象的生命周期交给Qt的对象树统一管理,如果放在栈上就可能会提前释放。


        下面我们就可以自己手写一个label。

  1.  在创建项目的时候选择创建C++类,我们的这个类是要继承QLabel的,所以也要包含QLabel头文件。

  2. 构造函数也要添加参数,和Widget类一样,要添加QWidget* parent。

  3. 源文件中定义构造函数,传入parent指针,将QLabel的对象添加到QWidget对象树中。

  4. 通过自定义析构函数来打印日志。

  5. 使用自定义的mylabel代替原有的QLabel,通过继承的方式给对象扩展析构函数的功能。

  6. 运行程序,发现界面中有文本,但是应用程序输出中没有我们要打印的内容。

  7. 通过日志显示出内容,说明析构函数执行了,虽然没有手动delete,但是把mylabel对象挂到了对象树中,窗口销毁后自动调用析构函数销毁对象树中的对象【注意】:这是虽然打印了,但是有乱码问题,这是因为汉字在不同的编码中是不同的,GBK占2字节,常用汉字UTF-8占3字节,所以具体要看使用的字符集。要解决这个问题就要让源文件和编译器的编码方式相同。

        使用QString也可以帮助我们自动处理编码。出现乱码还有一个原因就是使用了cout。其实Qt中提供了一个专门QDebug()工具,这就可以完成打印日志的工作,不需要我们自己在更改了。

        QDebug是Qt中的类,但是不会直接使用这个类,使用的是qDebug()这个宏,这个宏中就封装了QDebug对象,使用就类型与cout,也是重载了左移运算符(<<),最后也不用写endl。

        而且输出日志是在开发阶段中调试才需要的,并不想让用户看到,所以可以在代码中添加一个“开关”,这里就说明一种方法,就是在.pro文件中添加一行DEFINES += QT_NO_WARNING_OUTPUT\ QT_NO_DEBUG_OUTPUT

        所以在工程中不管是使用调试还是打印日志都可以处理bug,灵活选择就可以了。

编辑框

        想要完成Hello World程序,不止可以使用QLabel这样的控件,还可以通过使用编辑框来实现,编辑框又分为:

  • 单行编辑框 QLineEdit
  • 多行编辑框 QTextEdit

        在Qt Designer界面中左边的控件栏中有一栏Input Widgets,这一栏中就有Line Edit和Text Edit。

        我们可以通过拖拽的方式将Line Edit控件添加到界面中,之后可以在右边的属性栏中text栏显示的就是Hello World,也可以在这里双击进行修改。

        运行后就可以看到有一个编辑框,并且可以修改里面的内容。

        既然通过图形化界面拖拽的方式可以实现,那么也可以使用纯代码的方式实现。代码还是写在Widget.cpp中的构造函数里,方法与label的操作是差不多的。

按钮

        按钮这种方式也是可以实现Hello World程序的,还是在Qt Designer界面有一个Button栏,其中的Push Button就是一个普通按钮。

        通过拖拽和编辑也可以显示出Hello World,运行后就可以看到。

        这是个按钮,那就可以选中并点击,如果点击了会发现没有任何变化,这是因为没有点击的后续操作,这就要说到Qt中一种重要的机制就是信号槽机制,本质就是给按钮的点击操作关联上一个处理函数,当我们点击的时候就执行这个处理函数。这里先简单说一下,后续会详细说明的。

        我们需要通过一个connect()函数来完成这个动作,这个函数和网络中的客户端建立连接的函数名是一样的,但是不要弄混。Qt中的connect是QObject这个类提供的静态函数,作用就是连接信号和槽。

QMetaObject::Connection QObject::connect(const QObject *sender,\
                                         const char *signal, \
                                         const QObject *receiver, \
                                         const char *method, 
                                         Qt::ConnectionType type = Qt::AutoConnection)

参数:

  • sender:谁发出的信号
  • signal:发出的什么信号
  • receiver:谁来接收信号
  • method:处理函数

  • 传入函数的第一个参数是ui->pushButton,也就是访问form file(.ui)文件中的控件,Qt Designer创建一个控件就会给这个控件分配一个objectName属性,这个属性值要求是唯一的,这里又添加了一个,这个值也不会一样,而且可以手动修改。
  • 当qmake在执行.ui文件时就会根据objectName生成对应的C++代码(也就是ui_widget.h),所以第一个参数就是ui界面中objectName为pushButton这个空间要发出信号。
  • clicked就是点击按钮的时候会自动触发这个信号。

        接下来就是写这个处理函数,简单实现了一下。

        这里可能会有些疑问,界面中有一个Push Button控件,所以可以使用ui->pushButton这样的方式,但是&QPushButton::clicked,为什么可以这样写呢?

        那是因为在界面中添加一个Push Button,在ui_widget.h文件中,qmake根据form file中的.ui文件生成这段代码,其中就会包含一个QPushButton对象,对象的名字就是objectName。

 

        下面我们就看看纯代码是怎么实现,想要有个Push Button控件,那就要有一个对象,但是我们还想要实现点击按钮就交换,如果继续在构造函数中创建对象,handleClick函数就拿不到QPushButton对象,所以可以把这个对象添加到Widget类的成员变量中

        结果也是没有问题的。

       

        这两种方法的实现大同小异,区别就是:

  • 通过Qt Disigner创建按钮会更改form file下的.ui文件,xml文件生成ui_widget.h文件,文件中的Ui::Widget类里会自动包含QPushButton对象,这就不需要自己new对象了,这个对象会通过ui成员变量调用。
  • 纯代码就可以自己new对象,为保证其他成员函数能够访问这个变量还要添加到类中。

        所以这两种方式哪种更好用呢?

  • 如果当前程序界面内容比较固定,就会以图形化的方式来构造。
  • 如果当前程序界面内容要动态变化,就会以纯代码的方式来构造。
  • 所以这两种方式要配合使用。

 Qt 窗口坐标系

        Qt中的坐标体系是以Qt窗口的左上角为原点(0,0),X向右增加,Y向下增加。

yH5BAAAAAAALAAAAAAOAA4AAAIMhI+py+0Po5y02qsKADs=wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

        给Qt的某个控件设置位置就需要指定坐标,对于这个控件来说。坐标系原点就是相对于父窗口或父控件的,QWidget的父窗口就是显示器屏幕,QPushButton就只能在他的父控件也就是QWidget内部创建。

#include <QPushButton>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QPushButton* button = new QPushButton(this);
    button->setText("按钮"); // 如果不设置,默认位置就是父窗口的(0,0)坐标
    button->move(200, 300);

}

        如果想要给控件设置位置就要使用move()方法。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QPushButton* button = new QPushButton(this);
    button->setText("按钮"); // 如果不设置,默认位置就是父窗口的(0,0)坐标
    button->move(200, 300);

}

        这里move的第一个参数就是X坐标,第二个参数就是Y坐标,而参数的单位就是像素,显示器本身就是一大堆可以发光的亮点。

        电脑屏幕设置中的分辨率:在水平方向上有1920个像素,垂直方向上有1080个像素,显示器像素越大,画面越好。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1648905.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

互联网十万个为什么之什么是云计算

云计算是一种通过互联网提供计算资源和服务的技术。它允许用户随时随地访问和使用云平台上的数据、软件和硬件资源。在数字化时代&#xff0c;互联网已经成为基础设施。云计算使得数据中心能够像一台计算机一样去工作。通过互联网将算力以按需使用、按量付费的形式提供给用户&a…

[Kubernetes] Rancher 2.7.5 部署 k8s

server: 192.168.66.100 master: 192.168.66.101 node1: 192.16t8.66.102 文章目录 1.rancher server 安装docker2.部署k8s3.kubeconfig 1.rancher server 安装docker 所有主机开通ipv4 vi /etc/sysctl.conf#加入 net.ipv4.ip_forward 1#配置生效 sysctl -prancher-server开…

什么是企业出海?

本文节选自Odoo亚太金牌服务机构【开源智造】所编写的《企业数字化百科大全》如需获取完整的知识内容&#xff0c;请至开源智造官网免费获取。感谢网友一键三连&#xff1a;点赞、转发、收藏&#xff0c;您的支持是我们最大的前进动力&#xff01; 企业出海是什么意思&#xff…

压力测试-JMeter常用插件、服务器硬件监控

1.写在前面 在前一篇文章中&#xff0c;我们已经对jmeter有了一个入门的学习。 掌握了JMeter安装、入门、结果分析等内容&#xff0c;详情可查看这里&#xff1a;压力测试-JMeter安装、入门、结果分析 对于jmeter默认的插件&#xff0c;往往不太够&#xff0c;例如&#xff…

机器学习实践:超市商品购买关联规则分析

第2关&#xff1a;动手实现Apriori算法 任务描述 本关任务&#xff1a;编写 Python 代码实现 Apriori 算法。 相关知识 为了完成本关任务&#xff0c;你需要掌握 Apriori 算法流程。 Apriori 算法流程 Apriori 算法的两个输人参数分别是最小支持度和数据集。该算法首先会生成所…

LeetCode-DFS-树类-简单难度

关于二叉树的相关深度优先遍历类题目&#xff0c;重点在于掌握最基本的前中后序遍历&#xff0c;大多数题目都在围绕这套逻辑&#xff0c;找到处理节点的时机&#xff0c;以及停止遍历的条件&#xff0c;即可顺利完成。 二叉树前中后序遍历模板 所谓前中后序&#xff0c;指的…

好久不见,回来看看七年前的你

今天在网上搜东西&#xff0c;突然想到之前在网上记录的点滴成长&#xff0c;回来看看~ 来看看那些年走过的路&#xff0c;小伙还挺真实&#xff0c;有些想法~ 那时&#xff0c;一起在网上记录文字的人&#xff0c;也都慢慢失去了联系~ 确实&#xff0c;深有感触&#xff0c;…

【论文阅读笔记】MAS-SAM: Segment Any Marine Animal with Aggregated Features

1.论文介绍 MAS-SAM: Segment Any Marine Animal with Aggregated Features MAS-SAM&#xff1a;利用聚合特征分割任何海洋动物 Paper Code(空的) 2.摘要 最近&#xff0c;分割任何模型&#xff08;SAM&#xff09;在生成高质量的对象掩模和实现零拍摄图像分割方面表现出卓越…

超疏水TiO₂纳米纤维网膜的良好性能

超疏水TiO₂纳米纤维网膜是一种具有特殊性能的材料&#xff0c;它结合了TiO₂的光催化性能和超疏水表面的自清洁、防腐、防污等特性。这种材料在防水、自清洁、油水分离等领域具有广阔的应用前景。 制备超疏水TiO₂纳米纤维网膜的过程中&#xff0c;通过精确控制纺丝溶液的成分…

BFS Ekoparty 2022 -- Linux Kernel Exploitation Challenge

前言 昨天一个师傅给了我一道 linux kernel pwn 题目&#xff0c;然后我看了感觉非常有意思&#xff0c;题目也不算难&#xff08;在看了作者的提示下&#xff09;&#xff0c;所以就花时间做了做&#xff0c;在这里简单记录一下。这个题是 BFS Lab 2022 年的一道招聘题&#…

【优选算法】——Leetcode——202—— 快乐数

目录 1.题目 2. 题⽬分析: 3.简单证明&#xff1a; 4. 解法&#xff08;快慢指针&#xff09;&#xff1a; 算法思路&#xff1a; 补充知识&#xff1a;如何求⼀个数n每个位置上的数字的平⽅和。 总结概括 5.代码实现 1.C语言 2.C 1.题目 202. 快乐数 编写一个算法来…

国家电网某地电力公司网络硬件综合监控运维项目

国家电网某地电力公司是国家电网有限公司的子公司&#xff0c;负责当地电网规划、建设、运营和供电服务&#xff0c;下属多家地市供电企业和检修公司、信息通信公司等业务支撑实施机构。 项目现状 随着公司信息化建设加速&#xff0c;其信息内网中存在大量物理服务器、存储设备…

我独自升级崛起在哪下载 我独自升级崛起客户端下载教程

定于5月8日全球盛放的《我独自升级&#xff1a;崛起》——这一激动人心的动作角色扮演游戏巨作&#xff0c;汲取了同名动漫及网络漫画的精髓&#xff0c;誓将以其无与伦比的魅力&#xff0c;引领玩家迈入一个探索深远、规模宏大的奇幻之旅。游戏构筑在一个独一无二的网络武侠世…

英语学习笔记3——Sorry, sir.

Sorry, sir. 对不起&#xff0c;先生。 词汇 Vocabulary umbrella n. 伞&#xff0c;保护伞 注意读音 [ʌm’brelə] 英国人离不开雨伞。 please 请 特殊用法&#xff1a;让路&#xff08;升调&#xff09;      用餐礼仪&#xff08;平调&#xff09;      求求你…

【Toritoise SVN】SVN 怎么忽略文件夹下的所有文件但是不忽略文件夹本身

比如&#xff1a;忽略 Assets\StreamingAssets\LocalAsset文件夹下的所有文件但是不忽略LocalAsset这个文件夹 在TortoiseSVN中&#xff0c;你可以通过以下步骤来修改文件夹的svn:ignore属性&#xff1a; 打开Windows资源管理器&#xff0c;导航到你的工作副本中的Assets\Stre…

鸿蒙内核源码分析(互斥锁篇) | 互斥锁比自旋锁丰满多了

内核中哪些地方会用到互斥锁?看图: 图中是内核有关模块对互斥锁初始化,有文件,有内存,用消息队列等等,使用面非常的广.其实在给内核源码加注的过程中,会看到大量的自旋锁和互斥锁,它们的存在有序的保证了内核和应用程序的正常运行.是非常基础和重要的功能. 概述 自旋锁 和…

HIVE函数的基本使用

HIVE函数的基本使用 1.查看所有支持的函数 共289个 1)SHOW FUNCTIONS 查看所有支持的函数 共289个 2)SHOW FUNCTIONS LIKE "**" 模糊查询函数名 3)DESC FUNCTION 函数名 可以查看函数的具体使用方法 show functions; show functions like "*c…

【Python爬虫实战入门】:全球天气信息爬取

文章目录 一、爬取需求二、所需第三方库2.1 简介 三、实战案例四、完整代码 一、爬取需求 目标网站&#xff1a;http://www.weather.com.cn/textFC/hb.shtml 需求&#xff1a;爬取全国的天气&#xff08;获取城市以及最低气温&#xff09; 目标url&#xff1a;http://www.weath…

双热点的王炸组合!损失函数+Attention,精度与速度上实现SOTA!

损失函数注意力机制在深度学习领域是一个热门研究方向&#xff0c;它可以提高模型的性能和泛化能力&#xff0c;帮助我们构建更加精确且高效的模型。 具体来说&#xff1a; 通过结合注意力机制的聚焦能力和损失函数的优化指导&#xff0c;模型能够更精确地捕捉数据中的关键信息…

Vue3基础笔记(4)组件

目录 一.模版引用 二.组件组成 1.引入组件 2.注入组件 3.显示组件 三.组件嵌套关系 四.组件注册方式 五.组件传递数据 六.组件事件 一.模版引用 虽然Vue的声明性渲染模型为你抽象了大部分对DOM的直接操作&#xff0c;但在某些情况下&#xff0c;我们仍然需要直接访问底…