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

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.lryc.cn/news/617845.html

相关文章:

  • 力扣109:有序链表转换二叉搜索树
  • Linux下安装jdk
  • 分享一款基于STC8H8K32U-45I-LQFP48单片机的4路数字量输入输出模块
  • STM32——system文件夹
  • Day12 Maven高级
  • 2025牛客多校第七场 双生、象牙 个人题解
  • 大模型提示词工程实践:大语言模型文本转换实践
  • python之uv使用
  • 深度学习和神经网络最基础的mlp,从最基础的开始讲
  • OpenBMC中的snk-psu-manager:架构、原理与应用深度解析
  • 排错000
  • HTML应用指南:利用GET请求获取全国一加授权零售店位置信息
  • 工业相机与智能相机的区别
  • 【05】昊一源科技——昊一源科技 嵌入式笔试, 校招,题目记录及解析
  • 【unity实战】在Unity中实现不规则模型的网格建造系统(附项目源码)
  • 十二、Linux Shell脚本:正则表达式
  • Linux811 YUM;SHELL:if else fi,for
  • 学习嵌入式-IMX6ULL学习——中断
  • easyExcel嵌套子集合导出Excel
  • QT 高分屏不同缩放比例的自适应处理
  • GaussDB 数据库架构师修炼(十三)安全管理(1)-账号的管理
  • Spring Boot启动流程详解
  • 18.WEB 服务器
  • Logistic Loss Function|逻辑回归代价函数
  • 人工智能-python-机器学习-逻辑回归与K-Means算法:理论与应用
  • 【电机控制】FOC单电阻电流采样配置
  • DHCP 服务详解与部署
  • React 19 通用 ECharts 组件
  • Redis应⽤-缓存与分布式锁
  • Linux驱动学习day27天(USB驱动理论部分)