#include "widget.h"
#include "ui_widget.h"
#include <QFile>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnRead_clicked()
{
//1. 打开文件
//QFile file("D:/QT/test.txt");
QFile file;
file.setFileName("D:/QT/test.txt");
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
qDebug() << "file open error";
}
//2. 读取文件
char context[100] = {'\0'};
if( file.read(context,100) == -1) return;
//3. 输出文件内容
qDebug() << context;
file.close();
}
void Widget::on_btnWrite_clicked()
{
// 1.打开
QFile file("D:/QT/test2.txt");
file.open(QIODevice::WriteOnly | QIODevice::Text);
// 2. 写入
file.write("Program 45-QFile001 write something to This File 我是老陈");
// 3. 关闭
file.close();
}


void Widget::on_btnstrRead_clicked()
{
QFile file;
file.setFileName("D:/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;
}
file.close();
}
void Widget::on_btnstreamWrite_clicked()
{
QFile file;
file.setFileName("D:/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();
}
#include "widget.h"
#include "ui_widget.h"
#include <QFile>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
ui->setupUi(this);
// connect(this, SIGNAL(mysignal()), this, SLOT(myslot()));
// connect(this, SIGNAL(mysignalparams(int)), this, SLOT(myslotparams(int)));
// emit mysignal();
// emit mysignalparams(100);
}
Widget::~Widget()
{
delete ui;
}
//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();
}
//解释这串代码,写上注释
这段代码是一个 Qt 项目的 widget.cpp 文件,实现了基于文件操作的功能。它通过按钮点击事件调用不同的槽函数,分别实现 读取文本文件、写入文本文件、以流方式读写文件 的功能。
下面我将为你逐行添加详细的中文注释,并解释每个函数的作用和实现逻辑。
📁 包含头文件
cpp
深色版本
#include "widget.h"
#include "ui_widget.h" // 自动生成的 UI 类定义(包含界面控件)
#include <QFile> // Qt 提供的用于文件操作的类
🔧 构造函数和析构函数
cpp
深色版本
// 构造函数:初始化窗口部件
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
ui->setupUi(this); // 初始化由 .ui 文件生成的界面控件
}
// 析构函数:释放资源
Widget::~Widget()
{
delete ui; // 删除 UI 对象
}
📖 按钮点击事件处理函数
✅ 1. on_btnRead_clicked() —— 使用字节方式读取文件内容
cpp
深色版本
void Widget::on_btnRead_clicked()
{
QFile file;
file.setFileName("E:/QT/test.txt"); // 设置要打开的文件路径
// 尝试以只读+文本模式打开文件
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
qDebug() << "file open error"; // 打开失败,输出错误信息
return;
}
int size = file.size(); // 获取文件大小(字节数)
// 分配内存空间来存储读取的内容
char* context = new char(size); // 动态分配内存
char* con = (char *)malloc(sizeof(char)*size); // C风格内存分配(未使用)
// 从文件中读取最多100个字节到 context 缓冲区
if(file.read(context, 100) == -1) {
qDebug() << "read error";
return;
}
qDebug() << context; // 输出读取到的内容到调试控制台
file.close(); // 关闭文件
// 建议:记得在最后释放动态分配的内存
delete[] context;
free(con);
}
📌 注意问题:
new char(size)只分配了一个字符的空间,而不是字符串长度。应为:new char[size]- 推荐使用
QByteArray或QString来避免手动管理内存。
✅ 2. on_btnWrite_clicked() —— 写入文本文件
cpp
深色版本
void Widget::on_btnWrite_clicked()
{
// 创建并打开一个文件用于写入
QFile file("E:/QT/test2.txt");
// 以只写+文本模式打开文件(若文件不存在会自动创建)
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "file open error";
return;
}
// 向文件中写入字符串
file.write("Program 45-QFile001 write something to This File 我是测试");
// 关闭文件
file.close();
}
📌 说明:
- 如果文件已存在,原内容会被清空;
- 如果只想追加内容,请使用
QIODevice::Append模式。
✅ 3. on_btnstreamRead_clicked() —— 使用 QTextStream 流方式读取文件
cpp
深色版本
void Widget::on_btnstreamRead_clicked()
{
QFile file;
file.setFileName("E:/QT/test.txt"); // 设置文件路径
// 以只读+文本模式打开文件
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
qDebug() << "file open error";
return;
}
// 创建 QTextStream 对象,用于按流的方式读取文件
QTextStream in(&file);
// 设置编码格式为 UTF-8(支持中文)
in.setCodec("UTF-8");
// 逐行读取直到文件结尾
while(!in.atEnd()){
QString context = in.readLine(); // 读取一行内容
qDebug() << context; // 输出到调试控制台
qDebug() << "---------"; // 分隔线
}
file.close(); // 关闭文件
}
📌 优点:
- 支持中文;
- 更适合读取文本文件;
- 可以设置编码格式(如 UTF-8)。
✅ 4. on_btnstreamWrite_clicked() —— 使用 QTextStream 流方式写入文件
cpp
深色版本
void Widget::on_btnstreamWrite_clicked()
{
QFile file;
file.setFileName("E:/QT/test3.txt"); // 设置目标文件路径
// 以只写+文本模式打开文件
if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){
qDebug() << "file open error";
return;
}
// 创建 QTextStream 对象,用于流式写入
QTextStream out(&file);
// 设置编码格式为 UTF-8(支持中文)
out.setCodec("UTF-8");
// 写入字符串内容
out << "I write stream char to file ";
// 关闭文件
file.close();
}
📌 说明:
- 使用
<<运算符可以像std::cout一样写入数据; - 支持多语言(中文);
- 写入前文件内容会被清空。
📌 总结:功能一览
| 函数名 | 功能描述 |
|---|---|
on_btnRead_clicked() | 以字节形式读取文件内容(不推荐手动管理内存) |
on_btnWrite_clicked() | 写入指定文本到文件 |
on_btnstreamRead_clicked() | 使用 QTextStream 读取文本文件(推荐) |
on_btnstreamWrite_clicked() | 使用 QTextStream 写入文本文件(推荐) |
✅ 推荐改进点
| 改进项 | 建议 |
|---|---|
| 内存管理 | 避免手动 new/delete,改用 QByteArray 或 QString |
| 文件路径 | 使用相对路径或让用户选择文件(如 QFileDialog) |
| 异常处理 | 添加更完善的错误提示机制 |
| 字符串编码 | 始终设置 setCodec("UTF-8"),避免中文乱码 |
| 文件关闭 | 确保每次操作后都 close() 文件 |
| 日志输出 | 使用 qDebug() 而不是 std::cout |
如果你希望我帮你补充文件选择对话框(QFileDialog)、支持更多编码格式、或者把内容显示在界面上(如 QTextEdit),也可以继续提问 😊
#ifndef WIDGET_H
#define WIDGET_H
#include<iostream>
#include <QWidget>
#include<QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
//signals:
// void mysignal();
// void mysignalparams(int value);
//private slots:
// void myslot();
// void myslotparams(int value);
private slots:
void on_btnRead_clicked();
void on_btnWrite_clicked();
void on_btnstreamRead_clicked();
void on_btnstreamWrite_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
//解释这串代码,写上注释
这段代码是 widget.h 文件,它是 Qt 项目中一个自定义窗口部件类的头文件。它声明了一个名为 Widget 的类,继承自 QWidget,并定义了几个槽函数(slots),用于响应界面上按钮的点击事件。
📄 逐行解释与中文注释
cpp
深色版本
#ifndef WIDGET_H
#define WIDGET_H
- 头文件卫士(Header Guard):
- 防止该头文件被多次包含,避免重复定义类或变量。
- 如果
WIDGET_H没有被定义,则继续编译下面的内容; - 否则跳过整个文件。
cpp
深色版本
#include <iostream>
#include <QWidget>
#include <QDebug>
- 引入必要的头文件:
<iostream>:C++ 标准输入输出流,可用于std::cout;<QWidget>:Qt 提供的基础 GUI 类,所有界面控件都基于此类;<QDebug>:Qt 提供的调试输出工具,比std::cout更适合 Qt 程序使用。
cpp
深色版本
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
- Qt 使用的命名空间宏:
namespace Ui { class Widget; }是对由.ui文件生成的 UI 类的前置声明;- 实际上,
.ui文件会被 Qt Designer 转换为ui_widget.h文件,在运行时通过ui->xxx来访问界面上的控件。
cpp
深色版本
class Widget : public QWidget
{
Q_OBJECT
- 定义一个名为
Widget的类,继承自QWidget; Q_OBJECT是 Qt 的宏,表示这个类支持以下功能:- 信号与槽机制(Signal-Slot)
- 元对象系统(Meta Object)
- 动态属性、国际化等特性
cpp
深色版本
public:
Widget(QWidget *parent = nullptr);
~Widget();
- 构造函数和析构函数:
Widget(QWidget *parent = nullptr):构造函数,可接受父窗口指针,默认为nullptr;~Widget():析构函数,释放资源(如 UI 指针);
cpp
深色版本
//signals:
// void mysignal();
// void mysignalparams(int value);
//private slots:
// void myslot();
// void myslotparams(int value);
- 这些是之前定义但被注释掉的信号与槽函数:
mysignal()和mysignalparams(int)是自定义信号;myslot()和myslotparams(int)是对应的槽函数;
- 注释掉意味着当前不使用这些信号/槽。
cpp
深色版本
private slots:
void on_btnRead_clicked();
void on_btnWrite_clicked();
void on_btnstreamRead_clicked();
void on_btnstreamWrite_clicked();
- 声明四个私有槽函数,它们将响应界面上按钮的点击事件:
on_btnRead_clicked():读取文件内容;on_btnWrite_clicked():写入文件内容;on_btnstreamRead_clicked():以流方式读取文件;on_btnstreamWrite_clicked():以流方式写入文件;
- 函数名格式为
on_<objectName>_<signalName>(),这是 Qt 的自动连接机制要求的命名方式;- 例如:如果有一个按钮的
objectName是btnRead,它的clicked()信号会自动绑定到on_btnRead_clicked()。
- 例如:如果有一个按钮的
cpp
深色版本
private:
Ui::Widget *ui;
- 私有成员变量:
Ui::Widget *ui:指向由.ui文件生成的界面类的指针;- 通过
ui->控件名可以访问界面上的按钮、标签等控件。
cpp
深色版本
#endif // WIDGET_H
- 结束头文件卫士,与最开始的
#ifndef WIDGET_H配套使用。
✅ 总结结构图
| 部分 | 内容 |
|---|---|
| 头文件卫士 | #ifndef / #define / #endif |
| 引入头文件 | <iostream>、<QWidget>、<QDebug> |
| UI 前置声明 | namespace Ui { class Widget; } |
| 类定义 | class Widget : public QWidget |
| 支持 Qt 特性 | Q_OBJECT 宏 |
| 构造/析构函数 | 初始化窗口、释放资源 |
| 槽函数 | 四个按钮点击事件处理函数 |
| UI 成员指针 | Ui::Widget *ui;,用于操作界面控件 |
💡 小贴士
- 不要手动删除或修改
ui->setupUi(this);,这是加载.ui文件的关键语句; - 所有以
on_控件名_信号名()命名的函数都会被 Qt 自动连接; - 如果你添加了新的按钮并想让其触发某个函数,请确保:
- 控件名(
objectName)正确; - 函数名格式匹配;
- 在
.h中声明为private slots:; - 在
.cpp中实现该函数。
- 控件名(
如果你还需要我帮你补充完整 .cpp 文件内容,或者演示如何在界面上显示文件内容(比如用 QTextEdit),也可以继续提问 😊
wight.h和wight.cpp有什么关系和区别?
在C++编程中,.h文件(通常称为头文件)和.cpp文件(源文件)有着不同的角色和用途。以你提到的widget.h和widget.cpp为例,我们可以解释它们之间的关系和区别:
头文件(widget.h)
- 声明:头文件主要用于声明类、函数、变量以及包含其他必要的头文件。它定义了接口或合约,但不提供具体的实现细节。
- 包含保护:为了避免重复包含导致的编译错误,头文件通常会有预处理指令(如
#ifndef,#define,#endif)来防止多次包含。 - 依赖管理:通过头文件,你可以声明依赖而不必暴露实现细节。这有助于模块化设计,减少耦合。
源文件(widget.cpp)
- 实现:源文件包含了与头文件中声明对应的实现代码。也就是说,在这里你会找到所有函数的具体实现,包括成员函数的定义、全局函数等。
- 隐藏实现细节:将实现放在
.cpp文件中可以隐藏内部工作原理,只对外公开必要的接口。这对于库开发者来说尤其重要,因为他们可能不想让用户知道或者修改内部实现。 - 独立编译:每个
.cpp文件可以单独编译成目标文件(object file),然后由链接器将这些目标文件链接在一起形成最终的可执行程序。
关系
- 对应性:一个
.cpp文件通常会对应一个.h文件,尽管这不是强制性的。例如,widget.cpp实现了widget.h中声明的所有函数和方法。 - #include:在
.cpp文件中,通常会使用#include指令引入相应的.h文件,这样编译器就知道如何解析该源文件中的符号(如类、函数等)。
区别
- 功能不同:
.h文件主要负责声明,而.cpp文件负责实现。 - 编译过程不同:
.cpp文件会被编译为对象文件,而.h文件则不会直接参与编译过程,而是被其他源文件通过#include指令包含进来。
总之,widget.h和widget.cpp是相辅相成的,前者提供了类的蓝图,后者则是这个蓝图的具体实现。这种分离有助于提高代码的可维护性和重用性。
54

被折叠的 条评论
为什么被折叠?



