【QT】第一個QT程序 || 對象樹 || 編碼時的注意事項

一、編寫第一個 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;顯著提升開發效率。下面將從需求分析、技術選型、開發實現到優化部署&…