一、编写第一个 Qt 程序

1. 开发环境搭建

  • 安装 Qt Creator(推荐使用官方在线安装器)
  • 安装 Qt 库(如 Qt 5.15.2 或 Qt 6.x)
  • 配置编译器(MinGW / MSVC / GCC)

2. 创建一个简单的 Qt GUI 应用程序

  1. 打开 Qt Creator,点击“文件” -> “新建文件或项目”
  2. 选择应用程序类型:
    • Application -> Qt Widgets Application
  3. 设置项目名称和路径
  4. 选择构建套件(Kit)
  5. 输入类名(默认为 QApplicationQMainWindow/QDialog/QWidget
  6. 完成创建

3. 程序结构分析

生成的主要文件包括:

.pro文件

项目配置文件,定义构建参数

main.cpp

程序入口点

mainWindow.h/cpp

主窗口类定义和实现

ui_mainwindow.h

UI 自动生成的代码(由 .ui 文件转换而来)

示例代码:

#include <QApplication>
#include "mainwindow.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);MainWindow w;w.show();return a.exec(); // 进入主事件循环
}
#include "widget.h" // 创建生成时的文件
#include "ui_widget.h"
#include <QLabel>  // 包含标签的头文件Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this); // 将form file生成的界面和我们当前的widget进行关联起来// 创建对象的两种方法// QLabel label; // 在栈上创建QLabel* label = new QLabel(this); // 在堆上创建,推荐这种方法,还要传递 一个 this,给当前这个 lable 对象指定 父对象// 1. 设置标签内容label->setText((QString)("显式 Hello world"));label->setText("隐式 Hello World"); // QString 也提供了 C 风格字符串作为参数的构造函数来不显示构造 QString// 注意:由于QString 对应的头文件,已经被很多 Qt 内置的其他类给间接包含了.因此一般不需要显式包含 QString 头文件// 这里虽然有两次 setText,但是下面内容会覆盖上面内容// 2. 设置窗口大小setFixedSize(500, 400);// 3. 设置字体大小QFont font("楷体", 16);label->setFont(font);// 4. 设置标签内容显式位置label->move(200, 150);// 5. 设计标签字体颜色label->setStyleSheet("color:blue");
}Widget::~Widget()
{delete ui;
}

4.按钮实现第一个代码

图形化界面实现

1.双击:"widget.ui" 文件

2.拖拽控件至 ui 界面窗口并修改内容

  • 虽然那里有好几个按钮,但是我们这里用 Push Button(普通按钮)

3.构建并运行,效果如下所示

  • 这里的按钮的确可以点击,但是却没有任何反应,这个就设计到我们后面学的信号槽知识,后面会说的

  • QT 的信号槽机制:本质上就是给按钮的点击操作,关联上一个处理函数,当用户点击的时候,就会执行这个处理函数

这里我们的按钮没有任何功能,假如我们要实现一定的功能,那该怎么做呢?

打开 widget.ui 文件,查看设计的右下角,则有

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 按钮的点击操作 -- 信号槽// 在 Linux 网络编程那也有个connect 函数,那里用来给 TCP socket 建立连接的,写 TCP 客户端的时候,就需要先建立连接才能读写数据// ui->pushButton:谁发出的信号// &QPushButton::clicked:发出了啥信号,点击按钮的时候自动触发该信号// this: 谁来处理这个信号// Widget::handle:具体怎么处理connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick);  // 访问到 form file(ui 文件)中创建的控件}Widget::~Widget()
{delete ui;
}void Widget::handleClick()
{if(ui->pushButton->text() == "Hello World"){ui->pushButton->setText("Hello IsLand");}else{ui->pushButton->setText("Hello World");}
}

返回上级目录查看 ui_widget.h 文件

5.纯代码实现按钮

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);void handleClick();~Widget();private:Ui::Widget *ui;QPushButton* myButton;
};
#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);myButton = new QPushButton(this);myButton->setText("Hello World");connect(myButton, &QPushButton::clicked, this, &Widget::handleClick);  // 访问到 form file(ui 文件)中创建的控件
}Widget::~Widget()
{delete ui;
}void Widget::handleClick()
{if(myButton->text() == QString("Hello World")){myButton->setText("Hello IsLand");}else{myButton->setText("Hello World");}
}

实现效果:

两个版本比较:

  • 图形化实现:此时按钮对象不需要咱们自己 new。new 对象的操作已经是被 Qt 自动生成了而且这个按钮对象,已经作为 ui 对象里的一个成员变量了,也无需作为 Widget 的成员
  • 纯代码实现:按钮对象是咱们自己 new 的,为了保证其他函数中能够访问到这个变量,就需要把按钮对象,设定为 Widget 类的成员变量

实际开发中,是通过代码的方式构造界面为主,还是通过图形化界面的方式构造界面为主??

  • 这两种都很主要,难分主次!!
  • 如果你当前程序界面,界面内容是比较固定的,此时就会以 图形化 的方式来构造界面
  • 但是如果你的程序界面,经常要动态变化,此时就会以 代码 的方式来构造界面
  • 反正这两种方式哪种方便用哪个,也可以配合来使用

二、对象树机制(Parent-Child Object Tree)

1. 概念

Qt 提供了一种基于父子关系的对象管理机制 —— 对象树机制

当一个 QObject 子类对象被创建时,可以指定一个父对象(parent),该对象会自动加入到父对象的子对象列表中。

2. 特点

  • 当父对象被删除时,其所有子对象也会被自动删除。
  • 避免手动 delete,减少内存泄漏风险。
  • 只适用于继承自 QObject 的类。
    QWidget *parent = new QWidget;
    QPushButton *button = new QPushButton("Click Me", parent); // parent 作为按钮的父对象
    // 不需要手动 delete button
    delete parent; // 自动 delete button

    3. 注意事项

  • 如果使用了 setParent() 方法,也要注意生命周期管理。
  • 对于栈上对象(如局部变量),不能作为父对象传入堆上的对象。

三、验证对象树

Qt 的对象树机制是基于 QObject 类的父子关系实现的:

  • 当一个 QObject 子类对象被创建时,可以指定一个父对象。
  • 父对象被销毁时,会自动销毁所有子对象(递归)。
  • 可以通过 parent()children() 方法查看父子关系。

验证目标:

  1. 创建多个对象并建立父子关系
  2. 打印父子结构
  3. 删除父对象后检查子对象是否也被删除
  4. 使用调试器或日志辅助验证

示例代码:手动构建对象树并验证

1. 创建一个 Qt Widgets 应用(Qt Widgets Application

在你的主窗口类中编写如下代码:

mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QDebug>class MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:void buildObjectTree();
};#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) {buildObjectTree();
}MainWindow::~MainWindow() {qDebug() << "MainWindow destroyed";
}void MainWindow::buildObjectTree() {QObject* root = new QObject(this);  // this 是 MainWindow,作为 root 的 parentroot->setObjectName("Root");QObject* child1 = new QObject(root);child1->setObjectName("Child1");QObject* child2 = new QObject(root);child2->setObjectName("Child2");QObject* grandchild = new QObject(child1);grandchild->setObjectName("Grandchild");qDebug() << "Parent of" << grandchild->objectName() << "is" << grandchild->parent()->objectName();qDebug() << "Children of" << root->objectName() << ":";foreach(QObject* obj, root->children()) {qDebug() << " - " << obj->objectName();}
}
main.cpp
#include <QApplication>
#include "mainwindow.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}

输出日志验证对象树结构

运行程序后,在 Qt Creator 的 应用程序输出 面板中可以看到类似如下内容:

Parent of "Grandchild" is "Child1"
Children of "Root" :-  "Child1"-  "Child2"

说明对象树结构正确建立。

四、Qt 编程注意事项

1. 使用智能指针

虽然 Qt 有对象树机制,但在某些情况下建议使用 C++ 标准库中的智能指针:

  • std::unique_ptr:独占资源所有权
  • std::shared_ptr:共享资源所有权

例如:

auto ptr = std::make_unique<QWidget>();

2. 避免野指针

  • 在删除对象前确保没有其他地方引用它。
  • 使用 Qt 的父子对象机制来管理内存。

3. 信号与槽机制

  • Qt 提供了强大的通信机制:connect() 函数连接信号和槽函数。
  • 支持跨线程通信(需使用 Qt::QueuedConnection

示例:

connect(button, &QPushButton::clicked, this, &MyClass::handleClick);

4. 多线程编程

  • 推荐使用 QThreadQtConcurrent
  • 避免直接操作 UI 控件在非主线程中

5. 资源释放

  • 图片、文件等资源要记得关闭或释放
  • 使用 RAII(资源获取即初始化)原则进行管理

五个、、内存泄露问题排查与预防

1. 内存泄露常见原因

忘记 delete

动态分配内存后未释放

循环引用

A 引用 B,B 引用 A,导致无法释放

未正确使用父子对象

父对象未正确设置,导致子对象未被自动释放

信号槽未断开

长生命周期对象持有短生命周期对象的连接

2. 内存检测工具

  • Windows 平台
    • Visual Leak Detector (VLD)
    • CRT Debug Heap(调试模式下使用 _CrtDumpMemoryLeaks()
  • Linux/macOS 平台
    • Valgrind
    • AddressSanitizer

3. 使用 Qt 自带机制辅助检测

  • 启用调试输出
  • 使用 qDebug() 输出日志帮助定位问题
  • 使用 QScopedPointer(已过时,建议用 std::unique_ptr

4. 预防策略

  • 尽量使用智能指针或 Qt 的父子对象机制
  • 使用 RAII 技术封装资源管理
  • 定期使用内存检测工具测试
  • 避免手动 new/delete,除非必要

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

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

相关文章

多服务器IP白名单配置(使用redis stream实现)

应用背景 现在我有一个管理平台,可以通过代理连接到内网网站,但是这个代理服务器没有设置密码,所以需要IP白名单让指定用户才可以使用代理。 添加白名单流程图 流程描述: 登录管理平台成功后,管理平台的后台将这个登录的IP地址添加到redis,并设置过期时间为24小时redis…

Vue 3 Teleport 特性

目录 基本用法​ 搭配组件使用​ 禁用 Teleport​ 多个 Teleport 共享目标​ 延迟解析的 Teleport ​ 总结 <Teleport> 是一个内置组件&#xff0c;它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。 基本用法​ 有时我们可能会遇到这…

常用指令合集(DOS/Linux/git/Maven等)

文章目录 常用指令收集vmware 虚拟机联网设置ubuntu 常见问题设置apt 相关指令&#xff1a;gcc 编译相关指令 sqlite3VSCode 快捷键&#xff1a;收索引擎技巧&#xff08;google&#xff09;Intelideashell--LinxvimgitDOS:mavendockerkubectl 指令nginx配置redis-clientMySQLl…

ABP VNext + MassTransit:构建分布式事务与异步消息协作

ABP VNext MassTransit&#xff1a;构建分布式事务与异步消息协作 &#x1f680; &#x1f4da; 目录 ABP VNext MassTransit&#xff1a;构建分布式事务与异步消息协作 &#x1f680;&#x1f4da; 1. 背景与动机&#x1f6e0;️ 2. 环境与依赖&#x1f527; 3. 在 ABP 模块…

语义网技术

用通俗语言说语义网技术&#xff0c;以及它和现在互联网的关系 一、语义网技术&#xff1a;让网络“听懂人话”的智能升级 现有互联网就像一本巨大的“图文报纸”&#xff1a;我们人类看文章、图片能轻松理解意思&#xff0c;但计算机只能识别文字符号&#xff0c;不知道“苹…

pytorch学习—4.反向传播(用pytorch算梯度)

2. 线性模型 3.梯度下降算法 4.反向传播_哔哩哔哩_bilibili 4.1 代码复现 import torch import matplotlib.pyplot as pltx_data=[1.0,2.0,3.0] y_data=[2.0,4.0,6.0]#这里创建了一个PyTorch张量w,初始值为1.0,并且设置requires_grad=True, #这意味着在计算过程中,PyTo…

7类茶叶嫩芽图像分类数据集

在茶叶育种、溯源管理与自动采摘等智能农业场景中&#xff0c;茶树品种的识别与分类是一项关键任务。不同茶叶品种在嫩芽期表现出显著的形态差异&#xff0c;例如颜色、叶缘结构、芽头密度等。因此&#xff0c;基于图像的茶叶品种分类不仅具备实际应用价值&#xff0c;也为农业…

【Elasticsearch】Linux环境下安装Elasticsearch

一&#xff0c;前言 Elasticsearch&#xff08;简称 ES&#xff09;是一个基于 ​​Apache Lucene​​ 构建的开源分布式搜索与分析引擎。它支持​​实时数据处理​​&#xff0c;提供近实时的全文搜索能力&#xff0c;并通过 ​​JSON 格式的 RESTful API​​ 实现数据索引与检…

【数据结构--树于哨兵查找-1】

查找 从前到后- 线性查找 -就是顺序查找. 哨兵法查找–节省每次都要判断是否越界的这一步骤利于节省开销&#xff0c;从而提升效率。 参考我的程序 #include <stdio.h> #include <stdlib.h> #include <time.h> #include <stdbool.h>#define SIZE …

MyBatis修改(update)操作

1. 三步法口诀 “接口收对象&#xff0c;SQL全赋值&#xff0c;主键定目标” 2. 详细记忆点 | 步骤 | 口诀 | 说明与示例 | |--------------|----------------|----------------------------------------------------------------------------| | 1. 写接口 | “接口收对象…

Spring Boot 入门学习

一、 Web应用开发概述 什么是Web应用 1. Web应用 &#xff08;Web Application&#xff09;是一种运行在Web服务器上的软件程序&#xff0c;由用户通过Web浏览器进行访问和交互。 2.Web应用与传统的桌面应用不同&#xff0c;它不需要在个人计算机上安装特定的软件&#xff0…

深度解读概率与证据权重 -Probability and the Weighing of Evidence

以下是I.J.古德&#xff08;I.J. Good&#xff09;的经典著作 《概率与证据权衡》&#xff08;Probability and the Weighing of Evidence, 1950&#xff09; 的中文详细总结&#xff1a; 本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒…

跟着AI学习C#之项目实战-电商平台 Day6

&#x1f4c5; Day 6&#xff1a;后台管理系统开发&#xff08;Admin Panel&#xff09; ✅ 今日目标&#xff1a; 创建管理员页面布局实现商品管理&#xff08;CRUD&#xff09;实现订单管理&#xff08;查看、状态变更&#xff09;添加权限控制&#xff08;仅管理员可访问&…

使用OpcUaHelper在C# WinForms中连接OPC UA服务器并读取数据

使用OpcUaHelper在C# WinForms中连接OPC UA服务器并读取数据 下面是一个完整的示例&#xff0c;展示如何使用OpcUaHelper库在C# WinForms应用程序中连接OPC UA服务器并读取数据。 1. 准备工作 首先&#xff0c;确保你已经安装了OpcUaHelper NuGet包。可以通过NuGet包管理器控…

鸿蒙应用开发中的数据存储:SQLite与Preferences全面解析

在鸿蒙&#xff08;HarmonyOS&#xff09;应用开发中&#xff0c;数据存储是构建功能完整、用户体验良好的应用程序的关键环节。鸿蒙系统提供了多种数据存储解决方案&#xff0c;其中SQLite数据库和Preferences&#xff08;偏好设置&#xff09;是最常用的两种方式。本文将深入…

夏至之日,共赴实时 AI 之约:RTE Open Day@AGI Playground 2025 回顾

每年 RTE 开发者社区的重磅活动—— RTE Open Day &#xff0c;也在六月的 AGI Playground 现场开启今年的行程。这是 RTE Open Day 第五期现场&#xff0c;这期我们的关键词是 「Real-Time AI」 和 「Voice Agent」&#xff0c;不仅有来自社区的 16 个项目&#xff0c;还有两场…

Tomcat性能调优指南

文章目录 一、Tomcat性能调优概述为什么需要调优Tomcat&#xff1f; 二、Tomcat架构与性能关键点三、JVM调优1. 内存配置优化2. 垃圾回收优化3. 其他JVM优化参数 四、连接器(Connector)调优1. NIO vs APR/Native2. 高级NIO配置 五、线程池优化六、会话管理优化1. 会话超时配置2…

Swift 小技巧:用单边区间优雅处理模糊范围

进入正题之前先科普一下 Swift 区间的知识。 Swift 中的区间有两种类型&#xff1a;闭区间和半开区间。 闭区间&#xff1a;用 a...b 表示&#xff0c;包含 a 和 b。半开区间&#xff1a;用 a..<b 表示&#xff0c;包含 a 但不包含 b。 举个例子 想判断一个数字是否在 0 …

Tang Prime 20K板OV2640例程

准备用Tang Prime 20K开发板进行OV2640摄像头采集验证。 Tang Primer 20K是由开源硬件厂商SiPEED矽速科技推出&#xff0c;是一款以 GW2A-LV18PG256C8/I7 为主芯片的核心板&#xff0c;准备了 2 个扩展板&#xff0c;Dock 和 Lite。板卡包含有HDMI输出&#xff0c;DVP接口&…

基于Anaconda环境开发IntelliJ IDEA实用JSON转Java实体插件

在软件开发中&#xff0c;将JSON数据转换为Java实体类是常见需求。借助Anaconda环境强大的包管理能力与IntelliJ IDEA的插件开发体系&#xff0c;我们可以打造一款高效实用的JSON转Java实体插件&#xff0c;显著提升开发效率。下面将从需求分析、技术选型、开发实现到优化部署&…