Qt——实现”Hello World“、认识对象树与Qt坐标系

在创建项目时,使用的基类Base ClassQWidget

1. 使用图形化界面的方式实现“Hello World”

  1. 双击文件:widget.ui,进入designer模式:

在这里插入图片描述

  1. 在“控件盒子”的“Display Widgets”中找到“Label”,并拖放到白板中

    在这里插入图片描述

  2. 双击刚刚拖放到Label,输入"Hello World"

    在这里插入图片描述

  3. 最后直接运行即可:

    在这里插入图片描述

此时我们回过头来看widget.ui和编译生成的ui_widget.h文件,都发生了变化:

// widget.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>Widget</class><widget class="QWidget" name="Widget"><property name="geometry"><rect><x>0</x><y>0</y><width>800</width><height>600</height></rect></property><property name="windowTitle"><string>Widget</string></property><widget class="QLabel" name="label"><property name="geometry"><rect><x>230</x><y>110</y><width>81</width><height>51</height></rect></property><property name="text"><string>&quot;Hello World&quot;</string></property></widget></widget><resources/><connections/>
</ui>// ui_widget.h
/********************************************************************************
** Form generated from reading UI file 'widget.ui'
**
** Created by: Qt User Interface Compiler version 6.7.3
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/#ifndef UI_WIDGET_H
#define UI_WIDGET_H#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QWidget>QT_BEGIN_NAMESPACEclass Ui_Widget
{
public:QLabel *label;void setupUi(QWidget *Widget){if (Widget->objectName().isEmpty())Widget->setObjectName("Widget");Widget->resize(800, 600);label = new QLabel(Widget);label->setObjectName("label");label->setGeometry(QRect(230, 110, 81, 51));retranslateUi(Widget);QMetaObject::connectSlotsByName(Widget);} // setupUivoid retranslateUi(QWidget *Widget){Widget->setWindowTitle(QCoreApplication::translate("Widget", "Widget", nullptr));label->setText(QCoreApplication::translate("Widget", "\"Hello World\"", nullptr));} // retranslateUi};namespace Ui {class Widget: public Ui_Widget {};
} // namespace UiQT_END_NAMESPACE#endif // UI_WIDGET_H

2. 用代码的方式实现“Hello World”

一般来说,在实现图形化界面时,一般在继承类的构造函数中进行编写,如这里的widget.h

实现如下:

#include "widget.h"
#include "./ui_widget.h"
#include <QLabel>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QLabel* label = new QLabel(this);label->setText("\"Hello World\"");
}Widget::~Widget()
{delete ui;
}
  • Qt中每个类都有其同名的头文件,要使用类QLabel,就需要包含头文件<QLabel>

  • 在定义QLabel对象时,一般建议在堆上创建,同时建议将这个对象挂到对象树上,其父节点就是this

  • 方法label->setText的形参实际上是类型QString

    • Qt的诞生时间比C++标准形成的时间要早,因此,对于一些常见的数据结构,Qt自己造了一些轮子
    • 例如:QStringQVectorQListQMap
    • C++标准库中的容器也可以很方便的和Qt中的容器类相互转换

最后运行结果如图:

在这里插入图片描述

内存泄露问题

可以注意到,为了使用QLable对象,我们只用了new语句:QLabel* label = new QLabel(this);

我们在后面没有delete掉,不就内存泄露了吗?

这里可以告诉大家结论:

  • 上述代码在Qt中,不会产生内存泄露, 及在合适的时候 **,**​label会被自动释放
  • 原因就是,label对象被挂到对象树上了

对象树

引入对象树的主要目的,就是将诸如QLable这样的空间进行统一管理,这样就可以统一在合适的时候进行释放

  • 所谓合适的时候,就是图形界面窗口关闭/销毁的时候
  • 而如果不适用对象树,就可能导致一些资源的提前释放,具体到图形化界面中就可能导致一些控件元素不会正常显示
  • 在上面的代码中,将QLabel对象开辟在堆空间上,就是为了将其生命周期交给对象树进行管理

而如果开辟在栈上,就可能引发问题:

#include "widget.h"
#include "./ui_widget.h"
#include <QLabel>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// QLabel* label = new QLabel(this);// label->setText("\"Hello World\"");QLabel label(this);label.setText("\"Hello World\"");
}Widget::~Widget()
{delete ui;
}

运行:

在这里插入图片描述

发现预期的"Hello World"不见了

为了验证如果一个对象被挂到对象树上,会被自动清理,我么可以新建一个类myQLabel,其继承于QLabel

  1. 新建文件

在这里插入图片描述

  1. 选择C++中的C++ class

  2. 填写自定义类的信息

    在这里插入图片描述

代码如下:

// myQLabel.h
#ifndef MYQLABEL_H
#define MYQLABEL_H#include <QLabel>class myQLabel : public QLabel
{
public:myQLabel(QWidget* parent);~myQLabel();
};#endif // MYQLABEL_H// myQlabel.cpp
#include "myqlabel.h"#include <iostream>myQLabel::myQLabel(QWidget* parent): QLabel(parent) {}myQLabel::~myQLabel()
{std::cout << "MyQLabel 被释放" << std::endl;
}// widget.cpp
#include "widget.h"
#include "./ui_widget.h"
// #include <QLabel>
#include "myqlabel.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);myQLabel* label = new myQLabel(this);label->setText("\"Hello World\"");
}Widget::~Widget()
{delete ui;
}

可以看到,在关闭图形化窗口时,会输出:

在这里插入图片描述

乱码问题

从上面的输出我们可以看到,本来应该被打印的汉字“被释放”,输出竟然是乱码,这是为什么?

首先要说明结论:乱码之所以出现,其最主要的原因就是编码方式不一致

  • 源代码文件的编码格式
  • 终端(控制台)的显示编码格式
  • 字符串本身的编码处理方式

接下来,我们同样用该清楚,一个汉字到底占几个字节?

  • 对于这个问题,我们首先要区分汉字是采用哪种编码方式进行编码的——GBK,UTF-8
  • 如果采用GBK方式编码,那一个汉字就占2个字节
  • 如果采用UTF-8方式编码,那一个汉字就占2~4个字节,一般为3字节

我们先来查看输出汉字的文件myqlable.cpp是采用哪种方式进行编码:

在这里插入图片描述

  • 可以看到,编码方式为UTF-8
  • 而如果显示为ANSI,那么编码方式就是GBK

既然myqlabel.cpp的编码方式为utf8,但输出到控制台却出现乱码,说明终端控制台的编码方式就不是UTF-8

qDebug

为了解决这一问题,我们不是用C++标准的标准输出std::cout,而采用Qt提供的QDebug类:

#include "myqlabel.h"#include <QDebug>myQLabel::myQLabel(QWidget* parent): QLabel(parent) {}myQLabel::~myQLabel()
{qDebug() << "MyQLabel 被释放";
}
  • QDebug这个类重载了移位运算符<<,不直接使用类QDebug;而qdebug是一个宏,封装了QDebug对象,我们可以像使用std::cout一样来使用它
  • 使用qDebug()还有另一个好处,我们可以使用开关来对日志输出进行关闭, 防止日志信息对用户的干扰

3. 使用输入框实现 “Hello World”

3.1 使用图形化界面的方式

  1. 双击文件widget.ui,进入designer模式后找到控件:Line Edit

    在这里插入图片描述

  2. 将其拖放到白板中,双击控件,输入"Hello World"

    在这里插入图片描述

  3. 保存并运行即可

    在这里插入图片描述

3.2 使用代码的方式

QLabel的操作方式一样,将widget.cpp文件修改如下:

#include "widget.h"
#include "./ui_widget.h"#include <QLineEdit>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QLineEdit* line_edit = new QLineEdit(this);line_edit->setText("\"Hello World\"");
}Widget::~Widget()
{delete ui;
}

运行:

在这里插入图片描述

4. 使用按钮的方式实现“Hello World”

4.1 使用图形化界面的方式

  1. 双击文件widget.ui,进入designer模式后找到控件:Push Button

在这里插入图片描述

  1. 将其拖放到白板中,双击控件,输入"Hello World"

    在这里插入图片描述

    同时可以看到,在QObject中出现了objectName和对应的值:

    • Qt Designer创建一个控件的时候,此时会给这个控件分配一个objectName属性,这个属性的值要求在界面中是唯一的。我么也可以自己指定这个值

    • CMake在预处理.ui文件的时候,就会根据objectName来生成同名的类。例如上面的控件pushButton被生成的类名就是myPushButton

    • 我们可以在生成的ui_widget.h中看到这样的代码:

      在这里插入图片描述

  2. 进入编辑界面,修改widget.cpp如下:

// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void clickHandler();private:Ui::Widget *ui;
};
#endif // WIDGET_H//widget.cpp
#include "widget.h"
#include "./ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);connect(ui->myPushButton, &QPushButton::clicked, this, &Widget::clickHandler);
}Widget::~Widget()
{delete ui;
}// 当控件内容为“Hello World”,点击按钮后,就会变为“Hello Qt”
// 当空间内容为“Hello Qt”,点击按钮后,就会变为“Hello World“
void Widget::clickHandler()
{if (ui->myPushButton->text() == "\"Hello World\"") {ui->myPushButton->setText("\"Hello Qt\"");} else {ui->myPushButton->setText("\"Hello World\"");}
}

上述出现的connect是类QObject提供的静态函数,其功能是连接“信号”和“槽”,其4个参数的作用分别为:

在这里插入图片描述

在这里插入图片描述

4.2 使用代码的方式

代码如下:

// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QPushButton>QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void clickHandler();private:Ui::Widget *ui;QPushButton* myPushButton_ = nullptr;
};
#endif // WIDGET_H// widget.cpp
#include "widget.h"
#include "./ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), myPushButton_(new QPushButton(this))
{ui->setupUi(this);myPushButton_->setText("\"Hello World\"");connect(myPushButton_, &QPushButton::clicked, this, &Widget::clickHandler);
}Widget::~Widget()
{delete ui;
}void Widget::clickHandler()
{if (myPushButton_->text() == "\"Hello World\"") {myPushButton_->setText("\"Hello Qt\"");} else {myPushButton_->setText("\"Hello World\"");}
}

5. 图形化方式开发和代码方式开发

实际开发中,图形化方式开发界面和以纯代码方式代码界面都是很常用的方法

  • 如果界面内容是比较固定的,此时就会使用图形化界面来构造
  • 如果界面内容经常要动态变化,就需要以代码的方式进行开发
  • 此外,这两种方式也可以配合使用

6. Qt 坐标系

Qt的坐标系是 平面直角坐标系,其X轴从左往右增长,Y轴从上往下增长

在这里插入图片描述

坐标系的原点就是屏幕的左上角/窗口的左上角

给Qt的控件指定位置,就需要设置坐标,对于这个控件来说,其原点是相对于父窗口/父控件的

在这里插入图片描述

而如果要指定控件或窗口的位置,就需要用到对应的move成员函数:

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), myPushButton_(new QPushButton(this))
{ui->setupUi(this);myPushButton_->setText("\"Hello World\"");myPushButton_->move(200, 300);this->move(100, 200);
}
  • move的第一个参数为水平移动距离,单位为像素px
  • move的第二个参数为竖直移动距离,单位为像素px

运行如图:

在这里插入图片描述

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

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

相关文章

智能合约开发全流程实战指南

目录 灵感探索与概念验证合约开发常见问题 Hardhat 初始化项目问题合约编译错误处理智能合约设计缺陷 合约测试最佳实践 单元测试环境配置测试用例编写技巧测试覆盖率和策略常见测试失败原因 合约部署实战指南 部署到不同网络部署前准备事项部署后验证方法部署费用和Gas优化 合…

IPA1299至为芯替代TI ADS1299的脑机接口芯片

在脑机接口、神经科学研究和医疗电子设备领域&#xff0c;脑电信号采集芯片是连接生物电信号与数字世界的重要组件。目前&#xff0c;TI等国际厂商凭借技术优势占据市场主要份额&#xff0c;国内厂商在成本控制、供货周期和技术自主性方面面临挑战。英集芯推出的IPA1299低噪声多…

「数据获取」《中国海洋生态环境状况公报》(2001-2023年)(获取方式看绑定的资源)

01、数据简介在 2023 年的海洋环境监测工作中&#xff0c;监测范围广泛且细致。全年对 1359 个海洋环境质量国家控制点位进行了水质监测&#xff0c;这些点位分布在我国管辖的各大海域&#xff0c;能够全面反映海洋整体水质状况&#xff1b;对 230 个入海河流国家控制断面开展监…

通过限制网络访问来降低服务器被攻击风险的方法

限制网络访问是降低服务器被攻击风险的核心思路之一&#xff0c;因为绝大多数入侵都是从开放的网络入口开始的。思路是“减少暴露面 精确授权”&#xff0c;让服务器只对必要的人、必要的业务开放。我给你分成几个层次来说明&#xff0c;从最外层网络入口到最内层系统配置都涉…

python与JavaScript的区别

Python 与 JavaScript 的主要区别&#xff08;按常用维度划分&#xff09;维度PythonJavaScript诞生时间 / 背景1991 年&#xff0c;由 Guido van Rossum 设计&#xff0c;目标是“一种易读、易写的通用脚本语言”。1995 年&#xff0c;由 Brendan Eich 为 Netscape 浏览器诞生…

Java 比较器解析

一、比较器的核心作用与应用场景在 Java 编程中&#xff0c;数据比较是一个基础但重要的操作。对于基本数据类型&#xff08;如 int、double、boolean、char 等&#xff09;&#xff0c;Java 语言本身就提供了完整的比较运算符&#xff08;>、<、、>、<、!&#xf…

Java学习第一百二十一部分——HTTP

目录 一、前言简介 二、核心特性 三、通信基础结构 四、关键组件详解 五、性能演进——版本对比 六、开发者建议 七、总结归纳 一、前言简介 HTTP&#xff08;“H”yper“t”ext “T”ransfer “P”rotocol&#xff0c;超文本传输协议&#xff09;是互联网上应用最广泛…

记录RK3588的docker中启动rviz2报错

安装好rk3588 的docker&#xff0c;pull了ros的完整镜像后&#xff0c;想要启动rviz但是报错&#xff0c;下面是我的踩坑记录 0.原始的启动镜像的脚本&#xff1a; sudo docker run -it --rm --privileged --nethost -e DISPLAY$DISPLAY --namemy_image_name \-e DISPLAY$DIS…

ThingJS 新手学习技巧

一、ThingJS 基础认知 1.1 ThingJS 是什么 ThingJS 是一款基于 WebGL 技术的 3D 可视化开发平台&#xff0c;它为开发者提供了简单易用的 API 和丰富的 3D 场景组件&#xff0c;让开发者能够快速构建出高质量的 3D 可视化应用。无论是智慧园区、智慧楼宇、智慧交通还是工业监…

【软考架构】需求工程中,系统分析与设计的结构化方法

结构化方法诞生于20世纪70年代&#xff0c;是为了应对当时日益复杂的软件系统开发挑战&#xff08;如“软件危机”&#xff09;而提出的。它强调系统性、规范性、分解和抽象&#xff0c;目标是提高软件开发的效率、质量和可维护性&#xff0c;降低复杂性。 核心思想&#xff1a…

FPGA常用资源之IO概述

目录 一、前言 二、I/O资源 2.1 I/O端口资源 2.1.1 IOB 2.1.2 ILOGIC/OLOGIC 2.2 ZHOLD 2.3 IDDR/ODDR 2.4 IDELAY 2.5 ISERDES/OSERDES 2.6 IO Logic Resource连接 2.7 Device示意图 三、工程示例 3.1 工程代码 3.2 Device结果 一、前言 FPGA芯片从内部结构看主…

密集遮挡场景识别率↑31%!陌讯轻量化部署方案在智慧零售的实战解析

一、零售业痛点&#xff1a;当技术遇上客流洪流据《2024智慧零售技术白皮书》统计&#xff0c;高峰期超市顾客密度超3人/㎡时&#xff0c;​​目标漏检率高达48%​​。核心挑战包括&#xff1a;​​动态遮挡​​&#xff1a;购物车/货架造成的持续性目标截断​​计算瓶颈​​&a…

力扣(O(1) 时间插入、删除和获取随机元素)

一、题目分析&#xff08;一&#xff09;功能需求 我们需要实现 RandomizedSet 类&#xff0c;包含以下功能&#xff1a; RandomizedSet()&#xff1a;初始化数据结构。bool insert(int val)&#xff1a;当元素 val 不存在时&#xff0c;插入该元素并返回 true&#xff1b;若已…

前端开发的面试自我介绍与准备

前端面试自我介绍不知道怎么说的&#xff0c;直接参考下面的模板&#xff0c;然后换成你的经历 自我介绍控制在1分钟左右&#xff0c;千万不要说的太久&#xff0c;面试官会烦的&#xff0c;但是又不好意思打断你 切记面试是人和人面对面的交流&#xff0c;要有&#xff0c;面试…

10、系统规划与分析

一、系统规划步骤系统规划步骤对现有系统进行初步调查分析和确定系统目标分析子系统的组成和基本功能拟定系统的实施方案拟定系统的可行性研究指定系统建设方案系统规划阶段的产出物&#xff1a;可行性研究报告、系统设计任务书。习题1、拟定系统的实施方案是在系统规划阶段完成…

Nginx学习笔记(六)—— Nginx反向代理

&#x1f4da;Nginx学习笔记&#xff08;六&#xff09;—— Nginx反向代理 &#x1f4cc; 一、反向代理核心概念 本质原理&#xff1a; #mermaid-svg-UkFRDp2Ut7MK5T2N {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-s…

三伍微电子GSR2406 IoT FEM 2.4G PA 射频前端模组芯片

三伍微电子GSR2406 IoT FEM 2.4G PA 射频前端模组芯片规格书Product Description The GSR2406 is a high-performance, fully integrated RF front-end module (FEM) designed for Zigbee technology, Thread, and Bluetooth (including low energy) applications. The GSR2406…

开发避坑指南(24):RocketMQ磁盘空间告急异常处理,CODE 14 “service not available“解决方案

异常信息 Caused by: org.apache.rocketmq.client.exception.MQBrokerException: CODE: 14 DESC: service not available now, maybe disk full, CL: 0.94 CQ: 0.94 INDEX: 0.94, maybe your broker machine memory too small.异常背景 一个项目里面用到了rocketmq&#x…

开源WAF新标杆:雷池SafeLine用语义分析重构网站安全边界

文章目录前言【视频教程】1.安装Docker2.本地部署SafeLine3.使用SafeLine4.cpolar内网穿透工具安装5.创建远程连接公网地址6.固定Uptime Kuma公网地址前言 当个人或企业站点上线后面临的首要威胁往往来自网络攻击——据统计&#xff0c;超过60%的Web应用漏洞利用尝试在流量到达…

Mac M1探索AnythingLLM+SearXNG

SearXNG 能聚合来自多达 200 多个搜索服务&#xff0c;可私有化部署&#xff0c;并提供了灵活自定义选项。 AnythingLLMSearXNG&#xff0c;刚好能解决AnythingLLM因为网络限制导致web search不可用的问题。 1 安装docker 下载mac m1版本的docker并安装。 https://docs.dock…