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

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图像容器,用于绘制按钮图形
事件重写如 mousePressEventpaintEvent 等,实现交互和界面绘制
自定义信号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 元对象系统
自定义事件处理如 enterEventresizeEvent 等,用于响应用户交互
槽函数自动绑定使用 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 实现按钮样式
事件响应重写 mousePressEvententerEventleaveEvent 等响应用户交互
信号机制使用 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.lqws.cn/news/461935.html

相关文章:

  • Django中为api自定义一些装饰器:如参数校验等
  • GIFPlayer 使用指南:创建可调速的 GIF 播放器
  • 59-Oracle 10046事件-知识准备
  • Java面试复习指南:JVM原理、并发编程与Spring框架
  • Python UDP Socket 实时在线刷卡扫码POS消费机服务端示例源码
  • 「Linux文件及目录管理」通配符与文件名
  • 使用 Isaac Sim 模拟机器人
  • 蓝牙 5.0 新特性全解析:传输距离与速度提升的底层逻辑(面试宝典版)
  • day37
  • Redis数据结构之GEO
  • ROS1/ROS2中工作空间和工作包创建详解
  • WIFI原因造成ESP8266不断重启的解决办法
  • 创业知识概论
  • 大数据Hadoop集群搭建
  • 第五章 中央处理器
  • tkinter 的 pack() 布局管理器学习指南
  • 《汇编语言:基于X86处理器》第3章 汇编语言基础
  • 一个库,比如kott_tinymce ,想把的依赖库从kotti升级到kotti2 ,请问我是不是查找替换,把所有的kotti字符替换成kotti2就行了?
  • 加密货币:比特币
  • 如何进行IEC61850的一致性测试
  • linux——C程序的编译与调试
  • AR 眼镜之-条形码识别-实现方案
  • 7.3.1二叉排序树
  • 宽度优先遍历(bfs)(4)——解决拓扑排序
  • Python 中布尔值的使用:掌握逻辑判断的核心
  • phpstudy无法启动apache,80端口被占用,完美解决
  • Java常见八股-(6.算法+实施篇)
  • Linux——库文件生成和使用
  • 通过CDH安装Spark的详细指南
  • moments_object_model_3d这么理解