Qt、C++自定義按鈕、組件、事件編程開發練習,萬字實戰解析!!

x項目地址:https://gitee.com/fan-wenshan/qt_learn_button-andevent_zhengzhuo

項目界面截圖:

### 項目介紹:comstomSingal (Qt應用程序) 項目基本信息
- 項目類型 :Qt Widgets應用程序
- 開發環境 :Qt 5.12.12 + MinGW編譯器(支持32/64位構建)
- 項目路徑 : e:\QT\comstomSingal
- 構建配置 :支持Debug、Release和Profile三種構建模式 項目結構與核心文件
```

文件層級構成:
comstomSingal/
├──?comstomSingal.pro????????#?項目配置文件
├──?main.cpp?????????????????#?程序入口
├──?widget.h/.cpp????????????#?主窗口類
├──?widget.ui????????????????#?主窗口UI設計
├──?mybutton.h/.cpp??????????#?自定義按鈕組件
├──?res.qrc??????????????????#?資源文件配置
└──?icon/????????????????????#?圖標資源文件夾
``` 核心功能模塊 1. 主窗口功能(Widget類)
- 事件處理 :實現了鼠標進入/離開事件、滾輪事件、窗口關閉事件和窗口大小改變事件的重寫
? ```
? void?Widget::wheelEvent(QWheelEvent?
? *event)
? {
? ????qDebug()?<<?event->angleDelta();
? }
? ```
- 文件操作 :提供文件讀寫功能,支持文本文件的讀取和寫入,使用QFile和QTextStream
- 文件對話框 :集成QFileDialog實現文件選擇、保存功能
- UI交互 :包含按鈕、下拉框等控件,如 on_btnRead_clicked 、 on_btnWrite_clicked 等槽函數 2. 自定義按鈕組件(MyButton類)
- 繼承自QWidget,重寫了鼠標事件和繪制事件
- 支持自定義圖標顯示(使用QPixmap)
- 實現了自定義點擊信號(clicked()) 3. 資源管理
- 通過res.qrc管理圖標資源
- icon文件夾包含多種狀態的圖標文件(如c1.png、o1.png等) 技術特點
- 使用Qt信號槽機制實現UI交互
- 采用MVC設計模式分離界面與業務邏輯
- 支持中文編碼(文件操作中顯式設置UTF-8編碼)
- 模塊化設計,自定義組件可復用 構建與運行
- 默認構建目錄: E:\QT\build-comstomSingal-Desktop_Qt_5_12_12_MinGW_64_bit-Debug
- 支持32位和64位兩種架構構建
- 可通過Qt Creator直接編譯運行

源代碼展示:

comstomSingal.pro :

QT       += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \mybutton.cpp \widget.cppHEADERS += \mybutton.h \widget.hFORMS += \widget.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += targetRESOURCES += \res.qrc

你提供的這段代碼是一個 Qt 項目的 .pro 文件(項目配置文件),它告訴 qmake(Qt 的構建工具)如何編譯和鏈接你的項目。下面我將為你逐行詳細解釋這段 .pro 文件的每一部分,并說明其作用、用法以及背后的技術原理。


📁 一、基本結構與語法簡介

.pro 文件是 Qt 使用的項目描述文件,由 qmake 解析并生成對應的 Makefile,用于控制項目的編譯過程。

常見關鍵字:

關鍵字含義
QT需要使用的 Qt 模塊
CONFIG編譯配置選項
SOURCESC++ 源文件列表
HEADERS頭文件列表
FORMS.ui 文件(Qt Designer 設計的界面文件)
RESOURCES資源文件(.qrc)
TARGET最終生成的可執行文件名(默認為項目文件名)
INSTALLS安裝規則(如部署路徑)

🧾 二、逐行解析?.pro?文件內容

QT       += core gui
  • 添加 Qt 的核心模塊:
    • core:提供基礎類(如 QString、QList、QMap 等);
    • gui:提供圖形渲染、窗口系統集成等功能;
  • 這兩個模塊是 GUI 應用程序的基礎。
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
  • 條件語句:如果 Qt 版本大于 4(即 Qt5 或 Qt6),則添加?widgets?模塊;
  • widgets?是 Qt5 引入的模塊,包含傳統的 QWidget 控件庫(如 QPushButton、QLabel 等);
  • 如果使用的是 Qt4,則不啟用該模塊(因為 Qt4 的控件在 QtGui 中);
CONFIG += c++11
  • 啟用 C++11 標準支持;
  • 這樣就可以在項目中使用 Lambda 表達式、auto、nullptr 等現代 C++ 特性;
  • 如果你使用的是較新的 Qt(如 Qt5.14+ 或 Qt6),可以寫成?c++17?或?c++20
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
  • 注釋掉的宏定義,用于禁用 Qt 中被棄用的 API;
  • 如果取消注釋,使用這些舊 API 的代碼將無法通過編譯;
  • 0x060000?表示 Qt 6.0.0 及以前版本中廢棄的 API;
  • 這個設置有助于保持代碼現代化、避免依賴即將移除的功能;
SOURCES += \main.cpp \mybutton.cpp \widget.cpp
  • 列出所有 C++ 源文件;
  • \?是換行符,表示繼續下一行;
  • main.cpp:程序入口;
  • mybutton.cpp?和?widget.cpp:自定義控件和主窗口實現;
HEADERS += \mybutton.h \widget.h
  • 列出所有頭文件;
  • mybutton.hMyButton?類聲明;
  • widget.h:主窗口?Widget?類聲明;
FORMS += \widget.ui
  • 使用了 Qt Designer 設計的界面文件;
  • widget.ui?是一個 XML 文件,描述了界面布局和控件;
  • Qt 會自動將其轉換為?ui_widget.h?并生成?Ui::Widget?類;
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
  • 部署規則(安裝路徑):
    • 在 QNX 系統上,把可執行文件安裝到?/tmp/你的程序名/bin
    • 在其他 Unix 系統(非 Android)上,安裝到?/opt/你的程序名/bin
    • !isEmpty(...):如果設置了路徑,則加入?INSTALLS
    • INSTALLS?是 qmake 的安裝目標變量,表示哪些文件需要被復制到指定目錄;
RESOURCES += \res.qrc
  • 添加資源文件?res.qrc
  • .qrc?是 Qt 的資源文件格式,允許將圖片、圖標等資源嵌入到可執行文件中;
  • 可以通過?:/?路徑訪問資源(如?QPixmap(":/icon.png"));

🧩 三、總結?.pro?文件的作用

這個 .pro 文件主要完成了以下任務:

功能描述
指定 Qt 模塊包括 core、gui 和根據版本選擇是否使用 widgets
設置 C++ 標準支持 C++11
禁用棄用 API(可選)提高代碼質量
添加源碼和頭文件構建時包含所有必要的代碼
加載 UI 文件支持 Qt Designer 界面設計
配置部署路徑控制不同平臺下的安裝位置
加載資源文件支持內嵌資源(如圖標、圖片)

? 四、推薦優化建議

1. 更清晰地組織代碼

你可以將多個文件分組,提高可讀性:

SOURCES += main.cpp \mybutton.cpp \widget.cppHEADERS += mybutton.h \widget.hFORMS += widget.ui
RESOURCES += res.qrc

2. 明確指定目標名稱(可選)

如果你希望生成的可執行文件不是默認的 .pro 文件名,可以加:

TARGET = MyNotebookApp

3. 啟用調試信息(開發階段建議)

CONFIG += debug

或者更完整的調試配置:

CONFIG(debug, release) {message("Debug build")
} else {message("Release build")
}

📘 五、延伸知識:qmake 與 CMake 的區別

對比項qmakeCMake
使用方式.pro?文件CMakeLists.txt
Qt 親和度高(Qt 自帶)中(跨平臺)
配置復雜度簡單直觀更強大靈活
推薦用途小型 Qt 項目大型跨平臺項目

🧠 六、常見問題解答(FAQ)

? 我修改了?.pro?文件后,為什么沒生效?

  • 清理項目并重新運行 qmake:
    • 在 Qt Creator 中點擊 Build → Run qmake;
    • 或者刪除?build?目錄后重新構建;

? 如何添加圖標資源?

  • 把圖標文件(如?icon.ico)放到資源文件?res.qrc?中;
  • 在?.pro?中已經添加了?RESOURCES += res.qrc
  • 然后可以用?setWindowIcon(QIcon(":/icon.ico"));?設置窗口圖標;

如果你還有關于 .pro 文件的更多疑問,或者想了解如何遷移到 CMake、如何打包發布應用等高級話題,也歡迎繼續提問 😊

mybutton.h:

#ifndef MYBUTTON_H
#define MYBUTTON_H#include <QWidget>class MyButton : public QWidget
{Q_OBJECT
private:QPixmap pic;
public:explicit MyButton(QWidget *parent = nullptr);protected:void mousePressEvent(QMouseEvent *event) override;void leaveEvent(QEvent *event) override;void enterEvent(QEvent *event) override;void paintEvent(QPaintEvent *event) override;signals:void clicked();
};#endif // MYBUTTON_H

你提供的這段代碼是一個 自定義按鈕類的頭文件 mybutton.h,它繼承自 Qt 的 QWidget 類,并實現了基本的按鈕功能,包括響應鼠標點擊、進入/離開事件和繪制圖像。下面是對這段代碼的逐行詳細解釋 + 技術解析,幫助你理解它的結構和用途。


📌 一、頭文件保護宏(防止重復包含)

#ifndef MYBUTTON_H
#define MYBUTTON_H
  • 這是經典的?頭文件保護宏(include guard)
  • 防止在多個地方重復包含該頭文件導致編譯錯誤;
  • 如果沒有定義?MYBUTTON_H,則定義并繼續編譯;
  • 結束時用:
#endif // MYBUTTON_H

📦 二、包含必要的頭文件

#include <QWidget>
  • 包含 Qt 提供的基礎控件類?QWidget
  • 因為?MyButton?繼承自?QWidget,所以必須包含這個頭文件;

🔧 三、類定義:MyButton

class MyButton : public QWidget
{Q_OBJECT
  • 定義一個類?MyButton,繼承自?QWidget
  • Q_OBJECT?是 Qt 的宏,用于啟用:
    • 信號與槽機制(signals/slots);
    • 元對象系統(Meta Object System)
    • 所有使用了信號/槽或需要運行時信息的類都必須加上這個宏;

? 成員變量

private:QPixmap pic;
  • QPixmap?是 Qt 中用來處理圖像的對象;
  • pic?用于存儲按鈕的圖片資源;
  • 可以用于繪制按鈕背景、圖標等;

🎯 構造函數

public:explicit MyButton(QWidget *parent = nullptr);
  • 構造函數;
  • explicit?表示不能隱式轉換構造;
  • parent?參數是 Qt 中父子對象管理機制的一部分;
  • 默認值為?nullptr,表示可以作為頂層窗口;

🖱? 重寫事件處理函數

protected:void mousePressEvent(QMouseEvent *event) override;
  • 重寫鼠標按下事件;
  • 當用戶點擊按鈕時觸發;
  • 你可以在這里發射?clicked()?信號;
    void leaveEvent(QEvent *event) override;
  • 鼠標離開控件區域時觸發;
  • 可用于恢復按鈕樣式或取消高亮效果;
    void enterEvent(QEvent *event) override;
  • 鼠標進入控件區域時觸發;
  • 可用于實現按鈕的懸停效果;
    void paintEvent(QPaintEvent *event) override;
  • 繪制事件;
  • 用于在界面上繪制按鈕的外觀(如顯示圖片、邊框等);
  • 必須實現這個函數才能看到按鈕內容;

🔔 信號

signals:void clicked();
  • 自定義信號?clicked()
  • 當用戶點擊按鈕時,可以通過?emit clicked();?發射這個信號;
  • 允許外部連接到其他槽函數,實現按鈕點擊響應邏輯;

🧩 四、技術總結

技術點描述
Q_OBJECT?宏啟用信號/槽機制,支持 Qt 元對象系統
QPixmap圖像容器,用于繪制按鈕圖形
事件重寫如?mousePressEvent,?paintEvent?等,實現交互和界面繪制
自定義信號clicked()?用于通知外界按鈕被點擊
面向對象設計繼承 QWidget 實現自定義控件
Qt 事件模型通過重寫事件函數響應用戶操作

? 示例補充說明(配合?.cpp?文件)

以下是可能的 .cpp 文件中實現的內容概覽:

構造函數設置圖片(假設從資源加載)

MyButton::MyButton(QWidget *parent) : QWidget(parent), pic(":/images/button.png")
{setFixedSize(pic.size());  // 設置按鈕大小為圖片大小
}

鼠標按下事件(發射點擊信號)

void MyButton::mousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton) {emit clicked();  // 發射信號}QWidget::mousePressEvent(event);  // 調用父類實現
}

繪圖事件(繪制圖片)

void MyButton::paintEvent(QPaintEvent *event)
{QPainter painter(this);painter.drawPixmap(rect(), pic);  // 將圖片繪制到整個按鈕區域
}

💡 應用場景舉例

這種自定義按鈕常用于:

  • 實現帶有圖標或特殊樣式的按鈕;
  • 游戲中的 UI 控件(如開始游戲、暫停等);
  • 替代默認按鈕樣式,實現更豐富的視覺效果;
  • 學習 Qt 自定義控件開發的入門案例;

? 推薦改進方向

  1. 添加多種狀態圖片
    • 比如普通狀態、懸停狀態、按下狀態分別使用不同圖片;
  2. 支持縮放和樣式定制
    • 使用?QStyleOption?或?QIcon::Mode?改變按鈕外觀;
  3. 添加動畫效果
    • 在?enterEvent?和?leaveEvent?中添加漸變或放大效果;
  4. 封裝為可復用組件
    • 添加屬性(如?texticon)并通過?.ui?設計器使用;

如果你希望我幫你寫出完整的 .cpp 文件,或者教你如何在 Qt Designer 中使用這個按鈕,請繼續提問 😊

widget.cpp:

#ifndef WIDGET_H
#define WIDGET_H#include<iostream>
#include <QWidget>
#include<QDebug>
#include <QResizeEvent>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();//signals:
//        void mysignal();
//        void mysignalparams(int value);
//private slots:
//        void myslot();
//        void myslotparams(int value);
public:void enterEvent(QEvent *event)override;void leaveEvent(QEvent *event)override;void wheelEvent(QWheelEvent *event)override;void closeEvent(QCloseEvent *event)override;void resizeEvent(QResizeEvent *event)override;private slots:void on_btnRead_clicked();void on_btnWrite_clicked();void on_btnstreamRead_clicked();void on_btnstreamWrite_clicked();void on_btnQFileDialog_clicked();void on_btnSe_clicked();void on_btnSave_clicked();void oncurrentIndexChanged(int index);
private:Ui::Widget *ui;
};
#endif // WIDGET_H

這段代碼是 Qt C++ 項目中主窗口類 Widget 的頭文件 widget.h,它定義了一個繼承自 QWidget 的類,并包含了各種 事件處理函數、按鈕點擊槽函數、信號連接聲明 等。下面是對這段代碼的逐行詳細解釋 + 技術解析,幫助你全面理解它的功能和背后使用的技術。


📌 一、頭文件保護宏(防止重復包含)

#ifndef WIDGET_H
#define WIDGET_H
  • 這是經典的?頭文件保護宏(include guard)
  • 防止在多個地方重復包含該頭文件導致編譯錯誤;
  • 結束時用:
#endif // WIDGET_H

📦 二、引入必要的頭文件

#include <iostream>
#include <QWidget>
#include <QDebug>
#include <QResizeEvent>
頭文件作用
<iostream>提供標準輸入輸出流(如?std::cout),用于調試或日志輸出
<QWidget>Qt 基礎控件類,所有可視化控件都繼承自它
<QDebug>Qt 提供的調試輸出工具,替代?std::cout?更方便
<QResizeEvent>用于響應窗口大小變化事件

🔧 三、命名空間與 UI 類前置聲明

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
  • 這是 Qt 自動生成的代碼結構;
  • Ui::Widget?是由?.ui?文件通過?uic?工具生成的界面類;
  • 這里只是提前聲明這個類,避免在頭文件中直接包含?ui_widget.h

🧱 四、類定義:Widget

class Widget : public QWidget
{Q_OBJECT
  • 定義一個類?Widget,繼承自?QWidget
  • Q_OBJECT?是 Qt 的宏,用于啟用:
    • 信號與槽機制(signals/slots);
    • 元對象系統(Meta Object System)
    • 所有使用了信號/槽或需要運行時信息的類都必須加上這個宏;

🎯 五、構造函數與析構函數

public:Widget(QWidget *parent = nullptr);~Widget();
  • 構造函數:創建窗口對象;
  • 析構函數:釋放資源;
  • parent?參數用于 Qt 的父子對象管理機制;

🖱? 六、重寫的事件處理函數(override)

public:void enterEvent(QEvent *event) override;
  • 當鼠標進入控件區域時觸發;
  • 可用于實現懸停效果;
    void leaveEvent(QEvent *event) override;
  • 當鼠標離開控件區域時觸發;
  • 可用于取消高亮或動畫效果;
    void wheelEvent(QWheelEvent *event) override;
  • 鼠標滾輪事件;
  • 可用于縮放、滾動等操作;
    void closeEvent(QCloseEvent *event) override;
  • 窗口關閉前觸發;
  • 可用于彈出確認對話框或保存未保存的內容;
    void resizeEvent(QResizeEvent *event) override;
  • 窗口大小改變時觸發;
  • 可用于重新布局或更新控件尺寸;

🔔 七、信號與槽函數(被注釋掉)

//signals:
//    void mysignal();
//    void mysignalparams(int value);
//private slots:
//    void myslot();
//    void myslotparams(int value);
  • 這些是你預留的自定義信號和槽函數;
  • 被注釋掉了,可能是為了示例或后續擴展;
  • 使用方式:
    • 在適當的地方調用?emit mysignal();
    • 槽函數可以綁定到其他組件或邏輯中;

💡 八、按鈕點擊事件的槽函數(重要!)

這些函數是在 .ui 中設計的按鈕點擊事件對應的槽函數:

private slots:void on_btnRead_clicked();void on_btnWrite_clicked();void on_btnstreamRead_clicked();void on_btnstreamWrite_clicked();void on_btnQFileDialog_clicked();void on_btnSe_clicked();void on_btnSave_clicked();
函數名描述
on_btnRead_clicked()“讀取”按鈕點擊事件
on_btnWrite_clicked()“寫入”按鈕點擊事件
on_btnstreamRead_clicked()流式讀取按鈕(如 QTextStream)
on_btnstreamWrite_clicked()流式寫入按鈕
on_btnQFileDialog_clicked()彈出文件選擇對話框
on_btnSe_clicked()可能是“搜索”或“設置”按鈕
on_btnSave_clicked()保存按鈕(可能保存文本內容)

這些函數名符合 Qt 的自動連接規則:on_<控件名>_<信號名>()
Qt 會自動將這些函數連接到對應按鈕的 clicked() 信號上。


🔄 九、下拉框選項變化的槽函數

    void oncurrentIndexChanged(int index);
  • 當?QComboBox?下拉框的當前索引發生變化時觸發;
  • 通常用于根據用戶選擇切換編碼格式、語言、主題等;

🧩 十、私有成員變量

private:Ui::Widget *ui;
  • ui?是指向由?.ui?文件生成的界面對象的指針;
  • 通過它訪問界面上的所有控件(如按鈕、標簽、文本框等);

🧰 十一、完整技術總結

技術點描述
Q_OBJECT?宏啟用信號/槽機制,支持 Qt 元對象系統
自定義事件處理如?enterEvent,?resizeEvent?等,用于響應用戶交互
槽函數自動綁定使用?on_<控件名>_<事件名>()?格式自動連接按鈕事件
UI 類封裝使用?Ui::Widget?實現界面與邏輯分離
事件模型Qt 的事件驅動機制,響應窗口生命周期和用戶操作
資源管理通過父對象機制自動管理內存,避免內存泄漏
可擴展性預留了自定義信號/槽接口,便于后期擴展

? 示例補充說明(配合?.cpp?文件)

示例:on_btnRead_clicked()?函數(讀取文件內容)

void Widget::on_btnRead_clicked() {QFile file("example.txt");if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {qDebug() << "無法打開文件";return;}QTextStream in(&file);QString content = in.readAll();ui->textEdit->setPlainText(content);file.close();
}

示例:oncurrentIndexChanged(int)?函數(切換編碼)

void Widget::oncurrentIndexChanged(int index) {QString encoding = ui->comboBox->itemText(index);qDebug() << "當前編碼:" << encoding;// 可以在這里設置 QTextStream 的編碼格式
}

💡 應用場景舉例

這類 Widget 主窗口常用于:

  • 文本編輯器(記事本、日志查看器等);
  • 文件讀寫工具;
  • 編碼轉換工具;
  • 教學項目中的 GUI 編程練習;
  • 自定義控件開發的基礎框架;

? 推薦改進方向

  1. 添加撤銷/重做功能
    • 使用?QUndoStack?實現;
  2. 支持拖拽文件打開
    • 重寫?dragEnterEvent?和?dropEvent
  3. 美化界面
    • 使用樣式表(QSS)或 Qt Style Sheets;
  4. 國際化支持
    • 使用?tr()?包裹所有界面字符串;
  5. 多文檔支持
    • 使用?QMdiArea?實現類似 Word 的多文檔界面;

如果你希望我幫你寫出完整的 .cpp 文件,或者教你如何在 Qt Designer 中設計這個界面,請繼續提問 😊

main.cpp:

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

這段代碼是 Qt C++ 項目中的 程序入口文件 main.cpp,它的作用是啟動整個應用程序并顯示主窗口。雖然看起來很簡短,但它是整個 GUI 應用的“心臟”。下面我將為你逐行詳細解釋這段代碼,并說明其背后的技術原理。


📌 一、包含頭文件

#include "widget.h"
  • 包含自定義的主窗口類?Widget?的聲明;
  • 這個類繼承自?QWidget,是你應用程序的核心界面類;
  • 它定義了按鈕、事件處理、布局等內容;
#include <QApplication>
  • 包含 Qt 提供的?QApplication?類;
  • 是所有基于 Qt 的 GUI 應用程序的必需類;
  • 負責管理應用程序的生命周期、事件循環、界面初始化等;

🧱 二、程序入口函數:main()

int main(int argc, char *argv[])
  • 標準的 C/C++ 程序入口函數;
  • argc?和?argv?是命令行參數:
    • argc?表示參數數量;
    • argv?是一個數組,保存每個參數字符串;
  • 在 Qt 中,這些參數會被傳給?QApplication?來處理(如設置樣式、語言等);

? 創建 QApplication 對象

    QApplication a(argc, argv);
  • 創建一個?QApplication?實例?a
  • 每個 Qt GUI 應用必須有且只有一個?QApplication?對象;
  • 它會完成以下工作:
    • 初始化 Qt 內部系統(圖形驅動、輸入設備等);
    • 處理命令行參數;
    • 啟動主事件循環(event loop);
    • 管理資源釋放和退出邏輯;

?? 注意:如果你開發的是控制臺程序或非 GUI 程序,請使用 QCoreApplication


? 創建并顯示主窗口對象

    Widget w;w.show();
  • 創建一個?Widget?對象?w,這是你自定義的主窗口;
  • w.show()?顯示這個窗口;
  • show()?并不會立即繪制窗口,它只是將窗口標記為“需要顯示”,真正的繪制由 Qt 的事件系統完成;

? 啟動主事件循環

    return a.exec();
  • 調用?QApplication::exec()?啟動 Qt 的主事件循環;
  • 這是一個無限循環,直到用戶關閉最后一個窗口或調用?exit()?才會退出;
  • 在事件循環中,Qt 會不斷監聽并分發各種事件:
    • 鼠標點擊、鍵盤輸入;
    • 定時器事件;
    • 窗口重繪請求;
    • 自定義信號觸發;
  • 返回值通常用于操作系統判斷程序是否正常退出;

🧩 三、技術總結

技術點描述
QApplicationQt GUI 應用的核心類,管理應用程序生命周期
主事件循環(exec()Qt 的核心機制之一,負責響應用戶交互和系統事件
main()?函數程序入口,標準 C++ 結構
命令行參數處理支持通過命令行傳遞參數給 Qt 應用
窗口創建與顯示創建主窗口并調用?show()?顯示出來

💡 四、常見問題解答(FAQ)

? 為什么不能在?main()?中直接寫業務邏輯?

  • main()?函數只負責啟動應用;
  • 真正的界面交互、事件處理都在?QApplication::exec()?啟動的事件循環中進行;
  • 所以你應該把邏輯寫在?Widget?或其他類中,而不是?main()

? 如果我想讓窗口居中顯示怎么辦?

可以在 Widget 構造函數中添加:

#include <QDesktopWidget>// ...QRect screen = QApplication::desktop()->screenGeometry();
move((screen.width() - width()) / 2, (screen.height() - height()) / 2);

或者使用更現代的方式(Qt5.10+):

setWindowFlag(Qt::MSWindowsCenterCursor); // Windows 下有效

? 五、完整流程圖解(文字版)

main()
│
├── 創建 QApplication 對象 a
│
├── 創建主窗口 Widget 對象 w
│
├── 調用 w.show() 顯示窗口
│
└── 調用 a.exec() 啟動事件循環│├── 監聽用戶操作(鼠標、鍵盤)├── 觸發槽函數(按鈕點擊等)├── 刷新界面(paintEvent)└── 等待退出條件(如關閉窗口)

📘 六、延伸知識:Qt 程序結構概覽

一個完整的 Qt 項目通常包括:

文件名作用
main.cpp程序入口,創建 QApplication 和主窗口
widget.h/cpp主窗口類定義和實現
widget.ui使用 Qt Designer 設計的界面文件
.pro?文件qmake 項目配置文件
mybutton.h/cpp自定義控件類(可選)
res.qrc資源文件(圖標、圖片等)

? 示例擴展建議

1. 添加啟動畫面(QSplashScreen)

#include <QSplashScreen>QSplashScreen splash(QPixmap(":/images/splash.png"));
splash.show();QTimer::singleShot(2000, &splash, &QSplashScreen::close);

2. 設置應用程序圖標

a.setWindowIcon(QIcon(":/images/app_icon.ico"));

3. 添加國際化支持

QTranslator translator;
translator.load(":/translations/zh_CN.qm");
a.installTranslator(&translator);

如果你希望我幫你:

  • 寫出完整的?widget.cpp?文件;
  • 教你如何設計?.ui?文件;
  • 或者打包發布你的 Qt 應用;

歡迎繼續提問 😊

mybutton.cpp:

#include "mybutton.h"#include <QPainter>MyButton::MyButton(QWidget *parent) : QWidget(parent)
{pic.load(":/icon/o1.png");setFixedSize(pic.size());update();
}void MyButton::mousePressEvent(QMouseEvent *event)
{pic.load(":/icon/o3.png");update();emit clicked();
}void MyButton::leaveEvent(QEvent *event)
{pic.load(":/icon/o1.png");update();
//    emit clicked();
}void MyButton::enterEvent(QEvent *event)
{pic.load(":/icon/o2.png");update();
//    emit clicked();
}void MyButton::paintEvent(QPaintEvent *event)
{QPainter painter(this);painter.drawPixmap(rect(), pic);
}

你提供的這段代碼是 MyButton 類的實現文件 mybutton.cpp,它是一個自定義按鈕控件,繼承自 QWidget。這個按鈕通過加載不同的圖片來實現 普通狀態、懸停狀態和按下狀態 的視覺效果,并支持點擊信號(clicked())。

下面我將為你逐行詳細解析這段代碼,并講解它的設計思想、使用的技術以及可以優化的方向。


🧱 一、頭文件引入

 

cpp

深色版本

#include "mybutton.h"
  • 引入類定義頭文件;
  • 包含了?MyButton?類的聲明;
 

cpp

深色版本

#include <QPainter>
  • 引入 Qt 的繪圖類?QPainter
  • 用于在?paintEvent()?中繪制圖像;

🎯 二、構造函數:初始化按鈕外觀

 

cpp

深色版本

MyButton::MyButton(QWidget *parent) : QWidget(parent)
{pic.load(":/icon/o1.png");setFixedSize(pic.size());update();
}

? 解析:

  • pic.load(":/icon/o1.png")
    • 從資源文件中加載默認狀態的圖片;
    • :/icon/o1.png?是 Qt 資源系統的路徑;
  • setFixedSize(pic.size())
    • 設置按鈕為固定大小,等于圖片的尺寸;
    • 防止用戶調整窗口時按鈕變形;
  • update()
    • 請求重繪界面,觸發?paintEvent()
    • 保證構造完成后立即顯示初始圖片;

🖱? 三、鼠標事件處理

1.?mousePressEvent(QMouseEvent *event)?—— 點擊事件

 

cpp

深色版本

void MyButton::mousePressEvent(QMouseEvent *event)
{pic.load(":/icon/o3.png");update();emit clicked();
}
  • 當用戶按下鼠標左鍵時觸發;
  • 加載“按下狀態”的圖片;
  • 調用?update()?刷新界面;
  • 發射?clicked()?信號,通知外部響應按鈕點擊;

? 這個信號可以通過 connect(...) 綁定到其他槽函數,例如執行某個操作或跳轉頁面。


2.?leaveEvent(QEvent *event)?—— 鼠標離開事件

 

cpp

深色版本

void MyButton::leaveEvent(QEvent *event)
{pic.load(":/icon/o1.png");update();
//    emit clicked();
}
  • 鼠標移出按鈕區域時觸發;
  • 恢復“默認狀態”圖片;
  • 注釋掉的?emit clicked();?是無效邏輯,應刪除;

3.?enterEvent(QEvent *event)?—— 鼠標進入事件

 

cpp

深色版本

void MyButton::enterEvent(QEvent *event)
{pic.load(":/icon/o2.png");update();
//    emit clicked();
}
  • 鼠標進入按鈕區域時觸發;
  • 加載“懸停狀態”的圖片;
  • 同樣注釋掉的?emit clicked();?應該刪除;

🎨 四、繪制事件:paintEvent()

 

cpp

深色版本

void MyButton::paintEvent(QPaintEvent *event)
{QPainter painter(this);painter.drawPixmap(rect(), pic);
}
  • 所有可視化控件都必須實現這個函數;
  • 使用?QPainter?對象在界面上繪制內容;
  • drawPixmap(rect(), pic)
    • 將圖片繪制在整個按鈕區域內;
    • rect()?表示當前控件的矩形區域;

🧩 五、技術總結

技術點描述
自定義控件繼承?QWidget?實現一個新控件
圖像繪制使用?QPainter?和?QPixmap?實現按鈕樣式
事件響應重寫?mousePressEvent,?enterEvent,?leaveEvent?等響應用戶交互
信號機制使用?emit clicked()?提供按鈕點擊通知功能
資源系統使用?qrc?文件管理圖標資源,路徑格式為?:/

💡 六、應用舉例

你可以這樣使用這個按鈕:

1. 在?.ui?文件中手動添加一個?MyButton?控件(需注冊為提升控件)

或者:

2. 在代碼中創建并連接信號:

 

cpp

深色版本

MyButton *btn = new MyButton(this);
connect(btn, &MyButton::clicked, [=](){qDebug() << "按鈕被點擊了!";
});

? 七、建議改進方向

1. 增加多種狀態圖片的支持(更優雅)

可以提前將所有狀態圖片保存在成員變量中,避免頻繁加載:

private:QPixmap normalPic, hoverPic, pressedPic;

然后在構造函數中加載:

normalPic.load(":/icon/o1.png");
hoverPic.load(":/icon/o2.png");
pressedPic.load(":/icon/o3.png");

切換時只需賦值即可:

pic = pressedPic;
update();

2. 支持縮放和拉伸(適應不同分辨率)

可以使用 QPixmap::scaled() 方法縮放圖片:

painter.drawPixmap(rect(), pic.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));

3. 添加動畫效果(如淡入淡出)

可以結合 QPropertyAnimation 實現按鈕顏色漸變或大小變化的動畫效果。


4. 支持文字 + 圖標混合顯示

可以在按鈕上疊加文字說明:

painter.drawText(rect(), Qt::AlignCenter, "確定");

5. 支持設置圖片路徑(可配置化)

提供接口讓用戶動態設置按鈕圖片:

void MyButton::setNormalImage(const QString &path);
void MyButton::setHoverImage(const QString &path);
void MyButton::setPressedImage(const QString &path);

? 八、完整結構圖解(文字版)

MyButton (繼承 QWidget)
│
├── 構造函數
│   └── 加載默認圖片、設置大小、刷新界面
│
├── mousePressEvent()
│   └── 加載按下圖片、更新界面、發射 clicked()
│
├── enterEvent()
│   └── 加載懸停圖片、更新界面
│
├── leaveEvent()
│   └── 加載默認圖片、更新界面
│
└── paintEvent()└── 使用 QPainter 繪制當前圖片

📘 九、延伸知識:Qt 自定義控件開發流程

  1. 設計需求
    • 明確控件的功能、外觀、交互方式;
  2. 選擇基類
    • QWidget(最靈活)、QPushButton(已有功能豐富)等;
  3. 實現核心邏輯
    • 事件處理、繪制、狀態管理;
  4. 封裝成獨立組件
    • 可以打包為?.dll?或?.so?插件;
  5. 集成進 Qt Designer
    • 通過插件機制讓?.ui?編輯器識別你的控件;

如果你希望我幫你:

  • 完善這個按鈕類(支持多狀態、動畫、文字);
  • 教你如何將其添加到 Qt Designer 中;
  • 或者教你如何制作資源文件?.qrc; 歡迎繼續提問 😊
#include "widget.h"
#include "ui_widget.h"#include <QCloseEvent>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QWheelEvent>
#include "mybutton.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(oncurrentIndexChanged(int)));//    connect(this, SIGNAL(mysignal()), this, SLOT(myslot()));//    connect(this, SIGNAL(mysignalparams(int)), this, SLOT(myslotparams(int)));//    emit mysignal();//    emit mysignalparams(100);connect(ui->mybtn, &MyButton::clicked, [=](){qDebug() << "myButton is clicked";});
}Widget::~Widget()
{delete ui;
}void Widget::enterEvent(QEvent *event)
{qDebug() << "mouse enter";
}void Widget::leaveEvent(QEvent *event)
{qDebug() << "mouse leave";
}void Widget::wheelEvent(QWheelEvent *event)
{qDebug() << event->angleDelta();
}void Widget::closeEvent(QCloseEvent *event)
{int ret = QMessageBox::warning(this, tr("My Application"),tr("關閉窗口\n""你想關閉窗口嗎?"),QMessageBox::Ok | QMessageBox::No);switch (ret) {case QMessageBox::Ok :event->accept();break;case QMessageBox::No :event->ignore();break;}
}void Widget::resizeEvent(QResizeEvent *event)
{qDebug() << "oldSize:" << event->oldSize()<< "newSize:" << event->size();
}//void Widget::myslot()
//{
//    std::cout << "myslot" << std::endl;
//}//void Widget::myslotparams(int value)
//{
//    qDebug() << "myslotparams";
//    qDebug() << value;
//}void Widget::on_btnRead_clicked()
{//    QFile file("E:/QT2/test.txt");QFile file;file.setFileName("E:/QT/test.txt");if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){qDebug() << "file open error";}int size = file.size();char* context = new char(size);char* con = (char *)malloc(sizeof(char)*size);//    char context[100] = {"\0"};if(file.read(context, 100) == -1) return;qDebug() << context;file.close();
}void Widget::on_btnWrite_clicked()
{QFile file("E:/QT/test2.txt");file.open(QIODevice::WriteOnly | QIODevice::Text);file.write("Program 45-QFile001 write something to This File 我是測試");
}void Widget::on_btnstreamRead_clicked()
{QFile file;file.setFileName("E:/QT/test.txt");if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){qDebug() << "file open error";}QTextStream in(&file);in.setCodec("UTF-8");//QString context = in.read(file.size());while(!in.atEnd()){QString context = in.readLine();qDebug() << context;qDebug() << "---------";}file.close();
}void Widget::on_btnstreamWrite_clicked()
{QFile file;file.setFileName("E:/QT/test3.txt");if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){qDebug() << "file open error";}QTextStream out(&file);out.setCodec("UTF-8");out << "I write stream char to file ";file.close();
}void Widget::on_btnQFileDialog_clicked()
{QString fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), "E:/QT/",tr(" Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"));qDebug() << fileName;QFile file;file.setFileName(fileName);if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){qDebug() << "file open error";}QTextStream in(&file);in.setCodec("UTF-8");//QString context = in.read(file.size());while(!in.atEnd()){QString context = in.readLine();qDebug() << context;qDebug() << "---------";}file.close();
}void Widget::on_btnSe_clicked()
{//    int arr[120];//    for (int i : arr) {//    }QFileDialog qFileDialog;qFileDialog.setFileMode(QFileDialog::ExistingFiles);qFileDialog.setNameFilter("*.txt");qFileDialog.exec();QStringList qstrings = qFileDialog.selectedFiles();for(QString str : qstrings){qDebug() << str;}
}void Widget::on_btnSave_clicked()
{QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),"E:/QT/untitled.txt",tr("Text (*.txt *.doc)"));qDebug() << fileName;QFile file;file.setFileName(fileName);if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){qDebug() << "file open error";}QTextStream out(&file);out.setCodec("UTF-8");out << "Qdialog Write Data to the Txt File";file.close();
}void Widget::oncurrentIndexChanged(int index)
{qDebug() << index;qDebug() << ui->comboBox->currentText();
}

你提供的這段 widget.cpp 文件是一個 Qt 主窗口類 Widget 的實現文件,它完整地實現了:

  • 按鈕點擊事件處理
  • 文件讀寫操作(QFile)
  • 文本流讀寫(QTextStream)
  • 對話框使用(QFileDialog、QMessageBox)
  • 自定義事件響應(enter/leave/wheel/resize/close 事件)
  • 信號與槽連接機制

🧱 一、頭文件引入

#include "widget.h"
#include "ui_widget.h"
  • 引入主窗口類和 UI 自動生成的界面類;
  • ui_widget.h?是由?.ui?文件通過?uic?工具生成的;
#include <QCloseEvent>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QWheelEvent>
#include "mybutton.h"
  • 包含了必要的 Qt 類用于:
    • 窗口關閉事件處理;
    • 文件讀寫;
    • 對話框;
    • 自定義按鈕類;

🎯 二、構造函數:初始化 UI 和信號連接

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);
  • 調用?setupUi()?初始化界面布局;
  • 創建并綁定所有在?.ui?中設計的控件;
    connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(oncurrentIndexChanged(int)));
  • 連接下拉框的索引變化信號到對應的槽函數;
  • 使用的是傳統的?SIGNAL/SLOT?宏方式;
    connect(ui->mybtn, &MyButton::clicked, [=](){qDebug() << "myButton is clicked";});
  • 使用現代 Lambda 表達式連接?MyButton?的點擊信號;
  • 演示了如何對接自定義控件的信號;

? 推薦:對于 Qt5+,建議統一使用現代 Lambda 方式,更安全、可讀性更好。


🖱? 三、重寫的事件處理函數

1. 鼠標進入/離開事件

void Widget::enterEvent(QEvent *event)
{qDebug() << "mouse enter";
}void Widget::leaveEvent(QEvent *event)
{qDebug() << "mouse leave";
}
  • 用于調試或觸發懸停效果;
  • 可以配合樣式表實現動態 UI 效果;

2. 鼠標滾輪事件

void Widget::wheelEvent(QWheelEvent *event)
{qDebug() << event->angleDelta();
}
  • 獲取滾輪滾動方向和幅度;
  • 可用于縮放、切換頁面等;

3. 窗口關閉事件

void Widget::closeEvent(QCloseEvent *event)
{int ret = QMessageBox::warning(this, tr("My Application"),tr("關閉窗口\n""你想關閉窗口嗎?"),QMessageBox::Ok | QMessageBox::No);switch (ret) {case QMessageBox::Ok : event->accept(); break;case QMessageBox::No : event->ignore(); break;}
}
  • 用戶點擊關閉時彈出確認對話框;
  • 根據用戶選擇決定是否允許關閉;

4. 窗口大小改變事件

void Widget::resizeEvent(QResizeEvent *event)
{qDebug() << "oldSize:" << event->oldSize()<< "newSize:" << event->size();
}
  • 打印窗口大小變化前后尺寸;
  • 可用于動態調整布局或刷新內容;

💾 四、文件操作相關函數

1.?on_btnRead_clicked()?—— 原始方式讀取文件

void Widget::on_btnRead_clicked()
{QFile file("E:/QT/test.txt");if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){qDebug() << "file open error";}char* context = new char(100);file.read(context, 100);qDebug() << context;file.close();
}
  • 使用原始 C 風格讀取文件;
  • 存在潛在問題:
    • 分配內存不正確(應為?new char[100]);
    • 沒有檢查實際讀取長度;
    • 不推薦這種方式,建議改用?QTextStream

2.?on_btnWrite_clicked()?—— 寫入文件

void Widget::on_btnWrite_clicked()
{QFile file("E:/QT/test2.txt");file.open(QIODevice::WriteOnly | QIODevice::Text);file.write("Program 45-QFile001 write something to This File 我是測試");
}
  • 直接寫入字符串到文件;
  • 簡單實用;
  • 注意編碼問題(中文可能亂碼);

3.?on_btnstreamRead_clicked()?—— 使用 QTextStream 讀取

void Widget::on_btnstreamRead_clicked()
{QFile file("E:/QT/test.txt");file.open(QIODevice::ReadOnly | QIODevice::Text);QTextStream in(&file);in.setCodec("UTF-8");while (!in.atEnd()) {QString context = in.readLine();qDebug() << context;}file.close();
}
  • 推薦使用方式;
  • 支持 Unicode 編碼;
  • 更適合處理文本內容;

4.?on_btnstreamWrite_clicked()?—— 使用 QTextStream 寫入

void Widget::on_btnstreamWrite_clicked()
{QFile file("E:/QT/test3.txt");file.open(QIODevice::WriteOnly | QIODevice::Text);QTextStream out(&file);out.setCodec("UTF-8");out << "I write stream char to file ";file.close();
}
  • 同樣推薦使用;
  • 支持中文、換行符等;

5.?on_btnQFileDialog_clicked()?—— 打開文件并讀取內容

QString fileName = QFileDialog::getOpenFileName(...);
QFile file(fileName);
...
  • 彈出文件選擇對話框;
  • 讀取選中文件內容;
  • 顯示在控制臺;

6.?on_btnSe_clicked()?—— 多文件選擇

QFileDialog qFileDialog;
qFileDialog.setFileMode(QFileDialog::ExistingFiles);
qFileDialog.setNameFilter("*.txt");
qFileDialog.exec();QStringList qstrings = qFileDialog.selectedFiles();
for(QString str : qstrings){qDebug() << str;
}
  • 設置為多文件選擇模式;
  • 過濾?.txt?文件;
  • 獲取所有選中的文件路徑;

7.?on_btnSave_clicked()?—— 保存文件

QString fileName = QFileDialog::getSaveFileName(...);
QFile file(fileName);
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out << "Qdialog Write Data to the Txt File";
file.close();
  • 彈出“另存為”對話框;
  • 將內容寫入指定文件;

🔔 五、下拉框變化事件

void Widget::oncurrentIndexChanged(int index)
{qDebug() << index;qDebug() << ui->comboBox->currentText();
}
  • 當下拉框選項變化時觸發;
  • 輸出當前索引和顯示文本;
  • 可用于切換編碼、語言、主題等;

? 六、代碼優化建議

1. 內存管理問題(在?on_btnRead_clicked()?中)

char* context = new char(100); // ? 錯誤分配方式

應改為:

char* context = new char[100]; // ? 正確分配數組

但更推薦使用 QByteArrayQTextStream

QByteArray data = file.readAll();
qDebug() << data;

2. 使用智能指針避免內存泄漏(C++11+)

std::unique_ptr<char[]> context(new char[100]);

3. 使用現代 Lambda 連接方式(統一風格)

connect(ui->comboBox, &QComboBox::currentIndexChanged, this, &Widget::oncurrentIndexChanged);

4. 使用?tr()?包裹所有界面對話內容(支持國際化)

QMessageBox::warning(this, tr("My Application"), tr("確定要關閉窗口嗎?"));

📘 七、項目結構總結

功能模塊描述
界面交互QPushButton、QComboBox、QTextEdit 等控件
事件系統enter/leave/wheel/resize/close 事件
文件操作QFile + QTextStream 實現讀寫功能
對話框QFileDialog、QMessageBox
自定義控件MyButton,支持狀態切換和點擊信號
信號與槽使用傳統和現代兩種方式連接

🧩 八、技術棧一覽

技術用途
Qt Core基礎類(QString、QList 等)
Qt Gui圖形繪制、窗口系統集成
Qt Widgets提供傳統控件(QPushButton、QComboBox)
Qt Network(未使用)網絡通信
Qt Quick(未使用)QML 開發框架
Qt Designer可視化界面編輯工具

? 九、完整流程圖解(文字版)

Widget 構造函數
│
├── setupUi()
├── connect comboBox -> oncurrentIndexChanged
├── connect mybtn -> lambda clicked
│
└── 運行后響應各種事件│├── 鼠標進入/離開 → 控制臺輸出├── 滾輪 → 輸出角度├── 關閉 → 彈窗確認├── 調整大小 → 輸出尺寸├── 按鈕點擊 → 觸發對應函數│   └── 讀取/寫入文件、打開對話框等└── 下拉框變化 → 輸出當前項

📚 十、延伸學習建議

如果你希望繼續深入 Qt 開發,可以嘗試以下方向:

方向推薦內容
網絡編程QTcpSocket、QUdpSocket、QNetworkAccessManager
數據庫QSqlDatabase、SQLite、MySQL 驅動
多線程QThread、QtConcurrent、QRunnable
動畫QPropertyAnimation、QGraphicsView
自定義控件繼承 QWidget/QPushButton,重寫 paintEvent
國際化使用?tr()?和?.ts?文件生成多語言版本
發布打包使用 windeployqt 或 macdeployqt 打包程序
QML學習 Qt Quick,開發現代 UI

如果你希望我幫你:

  • 完善?MyButton?類,增加動畫或圖標+文字混合;
  • 教你如何將這個項目打包發布成獨立可執行程序;
  • 或者教你如何遷移到 CMake + Qt Quick(QML); 歡迎繼續提問 😊

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>971</width><height>683</height></rect></property><property name="windowTitle"><string>Widget</string></property><widget class="QPushButton" name="btnRead"><property name="geometry"><rect><x>70</x><y>90</y><width>101</width><height>51</height></rect></property><property name="text"><string>讀取文件</string></property></widget><widget class="QPushButton" name="btnWrite"><property name="geometry"><rect><x>190</x><y>90</y><width>101</width><height>51</height></rect></property><property name="text"><string>寫入文件</string></property></widget><widget class="QPushButton" name="btnstreamRead"><property name="geometry"><rect><x>310</x><y>90</y><width>101</width><height>51</height></rect></property><property name="text"><string>Stream讀取</string></property></widget><widget class="QPushButton" name="btnstreamWrite"><property name="geometry"><rect><x>430</x><y>90</y><width>101</width><height>51</height></rect></property><property name="text"><string>Stream寫入</string></property></widget><widget class="QPushButton" name="btnQFileDialog"><property name="geometry"><rect><x>70</x><y>180</y><width>101</width><height>51</height></rect></property><property name="text"><string>打開文件選擇框</string></property></widget><widget class="QPushButton" name="btnSe"><property name="geometry"><rect><x>190</x><y>180</y><width>101</width><height>51</height></rect></property><property name="text"><string>分步驟打開</string></property></widget><widget class="QPushButton" name="btnSave"><property name="geometry"><rect><x>310</x><y>180</y><width>101</width><height>51</height></rect></property><property name="text"><string>保存文件</string></property></widget><widget class="QComboBox" name="comboBox"><property name="geometry"><rect><x>430</x><y>180</y><width>101</width><height>51</height></rect></property><item><property name="text"><string>GBK</string></property></item><item><property name="text"><string>GB2312</string></property></item><item><property name="text"><string>UTF-8</string></property></item><item><property name="text"><string>ANSI</string></property></item><item><property name="text"><string>UTF-16</string></property></item></widget><widget class="MyButton" name="mybtn" native="true"><property name="geometry"><rect><x>110</x><y>330</y><width>120</width><height>80</height></rect></property></widget></widget><customwidgets><customwidget><class>MyButton</class><extends>QWidget</extends><header location="global">mybutton.h</header><container>1</container></customwidget></customwidgets><resources/><connections/>
</ui>

你提供的這段 XML 是 Qt Designer 生成的 .ui 文件,用于描述主窗口類 Widget 的界面布局和控件結構。它定義了一個功能完整的文件操作與自定義控件演示界面。


📄 一、整體結構概覽

<ui version="4.0"><class>Widget</class><widget class="QWidget" name="Widget">...</widget><customwidgets>...</customwidgets><resources/><connections/>
</ui>
  • <class>Widget</class>:表示這個?.ui?文件對應的是?Widget?類;
  • 根?<widget>?標簽:代表整個主窗口,繼承自?QWidget
  • <customwidgets>:注冊了自定義控件?MyButton
  • <resources/>:資源文件(圖標、圖片等)引用;
  • <connections/>:信號與槽連接關系(這里為空,說明是在代碼中動態連接);

🧱 二、界面元素詳解

? 主要控件一覽:

控件名類型功能
btnReadQPushButton原始方式讀取文件
btnWriteQPushButton寫入文件
btnstreamReadQPushButton使用 QTextStream 讀取文本
btnstreamWriteQPushButton使用 QTextStream 寫入文本
btnQFileDialogQPushButton打開文件選擇對話框
btnSeQPushButton多選文件對話框
btnSaveQPushButton保存文件對話框
comboBoxQComboBox編碼格式下拉框(GBK/UTF-8 等)
mybtnMyButton自定義按鈕控件

🎨 三、控件布局分析

所有控件都使用絕對坐標定位(通過 <geometry> 標簽),這是 Qt Designer 默認的方式,適用于靜態布局。

示例:按鈕?btnRead

<widget class="QPushButton" name="btnRead"><property name="geometry"><rect><x>70</x><y>90</y><width>101</width><height>51</height></rect></property><property name="text"><string>讀取文件</string></property>
</widget>
  • 位置:左上角?(70, 90)
  • 大小:寬?101px,高?51px
  • 顯示文字讀取文件

🧩 四、自定義控件注冊

<customwidgets><customwidget><class>MyButton</class><extends>QWidget</extends><header location="global">mybutton.h</header><container>1</container></customwidget>
</customwidgets>
  • <class>MyButton</class>:控件名稱;
  • <extends>QWidget</extends>:繼承自?QWidget
  • <header>:頭文件路徑;
  • <container>1</container>:表示是否可以在設計器中作為容器使用(通常為?0);

?? 注意:如果你在 .ui 中使用了自定義控件,必須確保:

  1. mybutton.h?存在且正確;
  2. 在項目中注冊該控件(或通過插件方式添加到 Qt Designer);
  3. 否則打開?.ui?文件會報錯;

📌 五、編碼風格建議

雖然 .ui 文件由 Qt Designer 自動生成,但你可以手動編輯以實現更靈活的控制。以下是一些推薦實踐:

1. 使用相對布局(Layout)代替絕對定位

目前是固定坐標,不適應窗口縮放。可以改為:

QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(ui->btnRead);
layout->addWidget(ui->btnWrite);
...
setLayout(layout);

或直接在 .ui 中拖動添加 Layout 容器。


2. 設置對象名時統一命名規范

比如 btn_ 開頭表示按鈕,cmb_ 表示下拉框:

  • btnRead?→?btn_read
  • comboBox?→?cmb_encoding

這樣更容易維護和查找。


3. 支持樣式表(QSS)

你可以為按鈕設置樣式:

<property name="styleSheet"><string notr="true">background-color: #FFA500; color: white;</string>
</property>

或者在代碼中設置:

ui->btnRead->setStyleSheet("background-color: #FFA500; color: white;");

🧪 六、運行效果預覽(文字版)

+---------------------------------------------------+
| Widget (標題)                                     |
+---------------------------------------------------+
|                                                   |
| [讀取文件] [寫入文件] [Stream讀取] [Stream寫入]     |
|                                                   |
| [打開文件選擇框] [分步驟打開] [保存文件] [下拉框]  |
|                                                   |
|                +------------------+               |
|                | 選項:GBK         |               |
|                |       UTF-8       |               |
|                |       ANSI        |               |
|                +------------------+               |
|                                                   |
|          +----------------------+                 |
|          |                      |                 |
|          |      自定義按鈕      |                 |
|          |                      |                 |
|          +----------------------+                 |
|                                                   |
+---------------------------------------------------+

📦 七、完整項目結構建議

文件作用
main.cpp程序入口
widget.h/cpp主窗口邏輯
ui_widget.h由?.ui?自動生成
mybutton.h/cpp自定義按鈕類
*.qrc資源文件(圖標、圖片)
Widget.ui可視化界面設計文件

📘 八、延伸學習建議

如果你希望我幫你:

  • 把?.ui?文件轉換為純代碼實現;
  • 教你如何將?MyButton?注冊為 Qt Designer 插件;
  • 或者教你如何用 QML 替代當前界面; 歡迎繼續提問 😊

如需我為你生成 .pro 文件、資源文件 .qrc 或幫助打包發布程序,也請告訴我!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/911984.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/911984.shtml
英文地址,請注明出處:http://en.pswp.cn/news/911984.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

商務年度總結匯報PPT模版分享

商務匯報&#xff0c;工作總結&#xff0c;畢業答辯&#xff0c;簡歷競聘PPT模版&#xff0c;創意年終匯報PPT模版&#xff0c;IDEAS商務匯報PPT模版&#xff0c;年度總結PPT模版&#xff0c;創意低多邊形PPT模版&#xff0c;商務型PPT模版&#xff0c;小清新創意花朵PPT模版&a…

電機設計仿真軟件學習DAY3——Maxwell界面功能+3D幾何模型繪制

"手把手教你玩轉電機&#xff01;每日更新教程&#xff0c;評論區答疑解惑&#xff0c;小白也能變大神&#xff01;" 目錄 maxwell基礎操作 一.Maxwell基礎操作&#xff1a;新建項目 二.maxwell3D界面 三.maxwell3D繪圖 3.1繪制圓柱體的方法 3.2繪制正方體的方法…

Apache 支持 HTTPS

證書文件 提取私鑰 openssl pkcs12 -in cert.pfx -nocerts -out private.key -nodes 打開命令行&#xff08;CMD 或 PowerShell&#xff09;&#xff0c;進入證書所在目錄&#xff0c;輸入上面命令&#xff0c;它會提示你輸入密碼&#xff0c;可以從 password.txt 中復制 提取證…

自然語言處理中的Transformer模型:超越RNN和LSTM

在人工智能的眾多領域中,**自然語言處理(Natural Language Processing, NLP)**無疑是最具挑戰性也最具前景的方向之一。從機器翻譯、文本摘要到情感分析和智能問答,NLP 旨在讓機器理解、解釋和生成人類語言。長期以來,循環神經網絡(Recurrent Neural Network, RNN)及其變…

vue3 new Date() 時間操作

在Vue 3中&#xff0c;你可以使用JavaScript的Date對象來處理日期和時間。如果你想創建一個新的Date對象表示當前時間減去一天&#xff0c;你可以使用以下幾種方法之一&#xff1a; 方法1&#xff1a;使用Date對象的setDate()方法 const now new Date(); now.setDate(now.ge…

WebRTC(八):SDP

SDP 概念 SDP 是一種描述多媒體通信會話的文本格式&#xff08;基于 MIME&#xff0c;RFC 4566&#xff09;。本身 不傳輸數據&#xff0c;僅用于在會話建立階段傳遞信息。常與 SIP&#xff08;VoIP&#xff09;、RTSP、WebRTC 等協議配合使用。 用途 描述媒體類型&#xf…

算法競賽>力扣>周賽 | weekly-contest-455

原文鏈接&#xff1a;算法競賽>力扣>周賽 | weekly-contest-455 3591.檢查元素頻次是否為質數 解題思路 統計每個元素出現的次數&#xff0c;判斷各次數是否為質數。由于次數<100&#xff0c;可用試除法判斷。 代碼實現 bool isPrime(int x) {if (x < 2)retur…

Vue 2快速實現px轉vw適配

Vue 2 Vue CLI 項目 px 轉 vw 完整使用指南 &#x1f4cb; 概述 本指南詳細介紹如何在 Vue 2 Vue CLI 項目中使用 postcss-px-to-viewport-8-plugin 插件&#xff0c;實現自動將 px 單位轉換為 vw 單位的響應式設計。 &#x1f680; 第一步&#xff1a;插件安裝 1.1 安裝…

Android MVVM模式介紹

一、介紹 1.Model(模型) Model代表應用程序的數據和業務邏輯。它負責處理數據的獲取、存儲和更新&#xff0c;例如從數據庫中檢索數據或通過網絡請求獲取數據。Model通常是與UI無關的部分&#xff0c;因此可以獨立測試和復用。 2. View&#xff08;視圖&#xff09; View是用…

WHAT - React Native 的 Expo Router

文章目錄 核心定義核心理念核心功能解析&#xff08;Features&#xff09;1. Native2. Shareable3. Offline-first4. Optimized5. Iteration6. Universal7. Discoverable 總結示例&#xff1a;頁面結構如何變成導航&#xff1f; 原文&#xff1a;https://docs.expo.dev/router/…

XML讀取和設置例子

在Qt C中&#xff0c;可以使用Qt的 QDomDocument類來讀取、更新和保存XML文件。這個類提供了對XML文檔的強大操作能力&#xff0c;支持通過DOM&#xff08;文檔對象模型&#xff09;對XML進行讀取、修改、添加和刪除節點等操作。 下面是一個詳細的例子&#xff0c;演示如何在Qt…

ubuntu 遠程桌面 xrdp + frp

經測試VNC啟動桌面&#xff0c;并非常規的桌面。 不如RDP好用。因此不用VNC server 一類。 直接安裝xrdp 實現UBUNTU 到UBUNTU 桌面的遠程共享。 sudo apt install xrdpsudo systemctl start xrdp查看狀態&#xff1a; sudo systemctl status xrdp ● xrdp.service - xrdp d…

el-table表頭添加說明

1、el-table-column添加render-header 2、編寫render函數 renderTipsHeader(h, { column }, item) {return h(span,[h(span, column.label),h(el-tooltip,{props:{effect:dark,content:item.headertip,placement:top},},[h(i, {class:el-icon-question,style:color:#C0C4CC;mar…

【AI論文】MultiFinBen:一個用于金融大語言模型評估的多語言、多模態且具備難度感知能力的基準測試集

摘要&#xff1a;近期&#xff0c;大型語言模型&#xff08;LLMs&#xff09;的進展加速了金融自然語言處理&#xff08;NLP&#xff09;及其應用的發展&#xff0c;然而現有的基準測試仍局限于單語言和單模態場景&#xff0c;往往過度依賴簡單任務&#xff0c;無法反映現實世界…

使用 .NET Core+GcExcel,生成 Excel 文件

引言 在當今數字化辦公和數據處理的大環境下&#xff0c;在線生成 Excel 文件成為了許多企業和開發者的需求。.NET Core 作為一個跨平臺的開源框架&#xff0c;具有高效、靈活等特點&#xff0c;而 GcExcel 是一款功能強大的 Excel 處理組件。將二者結合&#xff0c;可以方便地…

【代碼解析】opencv 安卓 SDK sample - 1 - HDR image

很久沒有寫安卓了&#xff0c;復習復習。用的是官方案例&#xff0c;詳見opencv-Android-sdk 包 // 定義包名&#xff0c;表示該類的組織路徑 package org.opencv.samples.tutorial1;// 導入所需的OpenCV和Android類庫 import org.opencv.android.CameraActivity; // OpenCV…

Web中間件性能調優指南:線程池、長連接與負載均衡的最佳實踐

目錄 引言一、Web容器線程池配置不當1.1 線程池參數的核心作用與影響1.2 線程池大小計算模型1.3 動態調優實踐 二、Keep-Alive機制配置缺陷2.1 Keep-Alive的工作原理2.2 典型配置問題與影響2.3 優化配置建議 三、負載均衡策略缺失3.1 負載均衡的核心價值3.2 主流負載均衡算法對…

15個AI模擬面試平臺 和 簡歷修改 / 真人面試平臺

對15個AI模擬面試平臺的詳細分析&#xff0c;每個平臺都將按照統一的框架進行評估。 補充重要的&#xff1a; 【1】AMA interview 聽說最好&#xff0c;最貴 1. Final Round AI 網址: https://www.finalroundai.com/ 功能深度剖析: Final Round AI 提供了一套全面的求職工具…

開始使用 Elastic AI Assistant for Observability 和阿里 Qwen3

這篇文章是繼之前的文章 “在本地電腦中部署阿里 Qwen3 大模型及連接到 Elasticsearch” 的續篇。如果你還沒有部署好自己的 Qwen3&#xff0c;那么請閱讀之前的那篇文章來安裝好環境&#xff0c;然后再繼續今天練習。在今天的文章中&#xff0c;我們將展示如何結合 Qwn3 和 El…

穩定幣技術全解:從貨幣錨定機制到區塊鏈金融基礎設施

引言&#xff1a;穩定幣的技術定位 根據國際清算銀行&#xff08;BIS&#xff09;2025年定義&#xff1a;穩定幣是以法定資產或算法機制維持價值穩定的區塊鏈代幣&#xff0c;其本質是傳統金融與加密技術的接口層。 核心價值&#xff1a;解決加密貨幣波動性問題 → 成為DeFi生態…