QT 记事本程序开发
一、引言
QT框架凭借其跨平台特性和简洁的API设计,成为开发GUI应用程序的理想选择。本文将详细讲解如何利用QT实现一个具备基础文件操作功能的记事本程序,涵盖新建、保存、另存为和退出功能的实现逻辑。
二、开发环境
-
QT版本: 6+
-
开发语言: C++
-
核心类库:
-
QMainWindow
主窗口框架 -
QTextEdit
文本编辑区域 -
QFileDialog
文件对话框 -
QFile
&QTextStream
文件读写
-
三、实现步骤
1. 项目创建与UI设计
通过QT Creator新建QMainWindow
项目,添加以下UI元素:
中央区域放置QTextEdit
组件用于文本编辑。
2. 核心功能实现
(1) 新建文件
逻辑:清空编辑区内容
void MainWindow::newFile()
{
//qDebug()<<"newFile()";
ui->textEdit->clear();
m_newFileName = "新建文本文件.txt";
this->setWindowTitle(m_newFileName);
}
(2) 打开文件
逻辑:打开选择文件对话框选择文件后打开,再读取文件内容。
// 文件对话框的三种模式:
// QFileDialog::getOpenFileName 打开文件
// QFileDialog::getSaveFileName 保存文件
// QFileDialog::getExistingDirectory 选择目录
void MainWindow::openFile()
{
//qDebug()<<"openFile()";
QString appFilePath = QCoreApplication::applicationDirPath();
//getOpenFileName 获取打开文件对话框
QString fileName = QFileDialog::getOpenFileName(this,
tr("请选择一个文件"),
appFilePath,
tr("Text Files (*.txt);;All Files (*)"));
if (!fileName.isEmpty()) {
openFileByName(fileName);
}
}
void MainWindow::openFileByName(const QString &fileName)
{
// 打开文件的逻辑
//qDebug() << "打开文件:" << file;
QFile file(fileName);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
m_saveFileName = fileName;
//一次性全部读取
QByteArray fileAll = file.readAll();
ui->textEdit->setText(QString(fileAll));
//一行一行读取
// QString fileData = "";
// while (!in.atEnd()) {
// QString line = in.readLine();
// //qDebug() << line;
// fileData.append(line + "\r\n");
// }
// ui->textEdit->setText(fileData);
file.close();
m_fileIsSave = false;
this->setWindowTitle(fileName);
ui->statusbar->showMessage(fileName);
//saveHistoryFileListIni(m_keyPrefix+QString::number(m_iniKeyisEmptyInde),fileName);
saveRecentFiles(fileName); // 更新历史记录
initMenu(); // 刷新菜单显示
}
}
(3) 保存文件
逻辑:若存在当前路径则直接保存,否则触发"另存为"
void MainWindow::saveFile()
{
QString appFilePath = QCoreApplication::applicationDirPath();
qDebug()<<"saveFile()"+appFilePath;
if(m_saveFileName.isEmpty())
{
QString appFilePath = QCoreApplication::applicationDirPath() + "//" + m_newFileName;
//getSaveFileName 获取保存文件对话框
QString fileName = QFileDialog::getSaveFileName(this, // 父窗口指针
tr("保存文件"), // 对话框标题
appFilePath, // 起始目录
tr("Text Files (*.txt);;All Files (*)")); // 文件过滤器
//qDebug()<<"saveFile():"<<fileName;
if(!fileName.isEmpty())
{
saveFileByName(fileName);
}
}
else
{
saveFileByName(m_saveFileName);
}
}
bool MainWindow::saveFileByName(const QString &fileName)
{
QFile file(fileName);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
// QTextStream out(&file);
// out << Qt::endl ; // 写入文本到文件
// file.close();
QByteArray ba;
ba.append(ui->textEdit->toPlainText().toUtf8());
file.write(ba);
file.close();
m_fileIsSave = true;
ui->statusbar->showMessage("保存成功."+fileName);
}
}
(4) 另存为
逻辑:通过文件对话框获取保存路径
void MainWindow::saveFileTo()
{
// qDebug()<<"saveFileTo()";
QString appFilePath = QCoreApplication::applicationDirPath();
QString fileName = QFileDialog::getSaveFileName(this, // 父窗口指针
tr("另存为文件"), // 对话框标题
appFilePath, // 起始目录
tr("Text Files (*.txt);;All Files (*)")); // 文件过滤器
//qDebug()<<"saveFile():"<<fileName;
if(!fileName.isEmpty())
{
saveFileByName(fileName);
}
}
(5) 退出程序
void MainWindow::exitApp()
{
qDebug()<<"exitApp()";
//QApplication::quit();
this->close();
}
(6) 初始化程序和菜单
void MainWindow::init()
{
m_iniName = "config.ini";
m_iniKeyisEmptyInde = -1;
m_intFileCount = 10;
m_iniLblName = "RecentFiles/";
m_keyPrefix = "file";
initMenu();
}
void MainWindow::initMenu()
{
//创建主菜单控件
QMenuBar *menuBar = new QMenuBar(this);
setMenuBar(menuBar);
//创建菜单(一级文件菜单)
QMenu *fileMenu = menuBar->addMenu("文件");
//fileMenu->setIcon(QIcon(":/res/file.svg"));
QAction *actionNew = fileMenu->addAction("新建");
actionNew->setIcon(QIcon(":/res/new.svg")); // 设置图标
actionNew->setShortcut(QKeySequence::New); // 设置快捷键(如 Ctrl+O)
QAction *actionOpen = fileMenu->addAction("打开");
actionOpen->setIcon(QIcon(":/res/open.svg")); // 设置图标
actionOpen->setShortcut(QKeySequence::Open); // 设置快捷键(如 Ctrl+O)
fileMenu->addSeparator();//添加分隔线
QAction *actionSave = fileMenu->addAction("保存");
actionSave->setIcon(QIcon(":/res/save.svg"));
actionSave->setShortcut(QKeySequence::Save);
QAction *actionSaveTo = fileMenu->addAction("另存为");
actionSaveTo->setIcon(QIcon(":/res/saveAs.svg"));
actionSaveTo->setShortcut(QKeySequence::SaveAs);
fileMenu->addSeparator();
QAction *actionRecent = fileMenu->addAction("最近访问");
actionRecent->setIcon(QIcon(":/res/recent.svg"));
//QAction *actionRecent1 = fileMenu->addAction("file1.txt");
loadRecentFiles(fileMenu);
fileMenu->addSeparator();
QAction *actionExit = new QAction("退出",this);
actionExit->setIcon(QIcon(":/res/exit.svg"));
actionExit->setShortcut(QKeySequence::SaveAs);
fileMenu->addAction(actionExit);// 退出放在最后
connect(actionNew, &QAction::triggered, this, &MainWindow::newFile);
connect(actionOpen, &QAction::triggered, this, &MainWindow::openFile);
connect(actionSave, &QAction::triggered, this, &MainWindow::saveFile);
connect(actionSaveTo, &QAction::triggered, this, &MainWindow::saveFileTo);
connect(actionExit, &QAction::triggered, this, &MainWindow::exitApp);
connect(ui->textEdit, &QTextEdit::textChanged, this, &MainWindow::textChangedSlots);
}
四、完整代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
//重写closeEvent 希望在窗口关闭前执行一些特定的操作(例如保存设置、提示用户等)
void closeEvent(QCloseEvent *event);
private:
void init();
void initMenu();
void loadRecentFiles(QMenu *fileMenu);
void newFile();
void openFile();
void saveFile();
void saveFileTo();
void exitApp();
void saveRecentFiles(const QString &newFile);
void openFileByName(const QString &fileName);
bool saveFileByName(const QString &fileName);
private slots:
void textChangedSlots();
private:
Ui::MainWindow *ui;
QString m_saveFileName;
QString m_newFileName;
bool m_fileIsSave;
int m_intFileCount;//配置文件中的总记录数
QString m_iniName;
QString m_iniLblName;
QString m_keyPrefix;
int m_iniKeyisEmptyInde;
QList<QString> m_recentList;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置窗口大小
resize(800,600);
setWindowTitle("文本文件APP");
m_fileIsSave = true;
init();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::init()
{
m_iniName = "config.ini";
m_iniKeyisEmptyInde = -1;
m_intFileCount = 10;
m_iniLblName = "RecentFiles/";
m_keyPrefix = "file";
initMenu();
}
void MainWindow::initMenu()
{
//创建主菜单控件
QMenuBar *menuBar = new QMenuBar(this);
setMenuBar(menuBar);
//创建菜单(一级文件菜单)
QMenu *fileMenu = menuBar->addMenu("文件");
//fileMenu->setIcon(QIcon(":/res/file.svg"));
QAction *actionNew = fileMenu->addAction("新建");
actionNew->setIcon(QIcon(":/res/new.svg")); // 设置图标
actionNew->setShortcut(QKeySequence::New); // 设置快捷键(如 Ctrl+O)
QAction *actionOpen = fileMenu->addAction("打开");
actionOpen->setIcon(QIcon(":/res/open.svg")); // 设置图标
actionOpen->setShortcut(QKeySequence::Open); // 设置快捷键(如 Ctrl+O)
fileMenu->addSeparator();//添加分隔线
QAction *actionSave = fileMenu->addAction("保存");
actionSave->setIcon(QIcon(":/res/save.svg"));
actionSave->setShortcut(QKeySequence::Save);
QAction *actionSaveTo = fileMenu->addAction("另存为");
actionSaveTo->setIcon(QIcon(":/res/saveAs.svg"));
actionSaveTo->setShortcut(QKeySequence::SaveAs);
fileMenu->addSeparator();
QAction *actionRecent = fileMenu->addAction("最近访问");
actionRecent->setIcon(QIcon(":/res/recent.svg"));
//QAction *actionRecent1 = fileMenu->addAction("file1.txt");
loadRecentFiles(fileMenu);
fileMenu->addSeparator();
QAction *actionExit = new QAction("退出",this);
actionExit->setIcon(QIcon(":/res/exit.svg"));
actionExit->setShortcut(QKeySequence::SaveAs);
fileMenu->addAction(actionExit);// 退出放在最后
connect(actionNew, &QAction::triggered, this, &MainWindow::newFile);
connect(actionOpen, &QAction::triggered, this, &MainWindow::openFile);
connect(actionSave, &QAction::triggered, this, &MainWindow::saveFile);
connect(actionSaveTo, &QAction::triggered, this, &MainWindow::saveFileTo);
connect(actionExit, &QAction::triggered, this, &MainWindow::exitApp);
connect(ui->textEdit, &QTextEdit::textChanged, this, &MainWindow::textChangedSlots);
}
void MainWindow::loadRecentFiles(QMenu *fileMenu)
{
m_recentList.clear();
QSettings settings(m_iniName,QSettings::IniFormat);
for(int i = 0;i < m_intFileCount;i++)
{
QString value = settings.value(m_iniLblName + m_keyPrefix + QString::number(i)).toString();
if(!value.isEmpty())
{
m_recentList<<value;
}
else
{
break;
}
}
foreach (const QString &file, m_recentList) {
QAction *action = fileMenu->addAction(file);
connect(action, &QAction::triggered, [this, file]() {
openFileByName(file);
});
}
// 如果没有历史文件,可选添加禁用项
if (m_recentList.isEmpty()) {
QAction *noRecent = fileMenu->addAction("无最近文件");
noRecent->setEnabled(false);
}
}
//重写closeEvent 希望在窗口关闭前执行一些特定的操作(例如保存设置、提示用户等)
void MainWindow::closeEvent(QCloseEvent *event)
{
if(m_fileIsSave == false)
{
// 执行一些清理操作
QMessageBox::StandardButton msgResult = QMessageBox::question(this,"系统提示","你的文件未保存是否保存后退出?");
if(msgResult == QMessageBox::Yes)
{
//执行保存
saveFile();
}
}
// ...
// 调用基类的closeEvent以确保窗口正常关闭
QMainWindow::closeEvent(event);
}
void MainWindow::newFile()
{
//qDebug()<<"newFile()";
ui->textEdit->clear();
m_newFileName = "新建文本文件.txt";
this->setWindowTitle(m_newFileName);
}
// 文件对话框的三种模式:
// QFileDialog::getOpenFileName 打开文件
// QFileDialog::getSaveFileName 保存文件
// QFileDialog::getExistingDirectory 选择目录
void MainWindow::openFile()
{
//qDebug()<<"openFile()";
QString appFilePath = QCoreApplication::applicationDirPath();
//getOpenFileName 获取打开文件对话框
QString fileName = QFileDialog::getOpenFileName(this,
tr("请选择一个文件"),
appFilePath,
tr("Text Files (*.txt);;All Files (*)"));
if (!fileName.isEmpty()) {
openFileByName(fileName);
}
}
void MainWindow::saveFile()
{
QString appFilePath = QCoreApplication::applicationDirPath();
qDebug()<<"saveFile()"+appFilePath;
if(m_saveFileName.isEmpty())
{
QString appFilePath = QCoreApplication::applicationDirPath() + "//" + m_newFileName;
//getSaveFileName 获取保存文件对话框
QString fileName = QFileDialog::getSaveFileName(this, // 父窗口指针
tr("保存文件"), // 对话框标题
appFilePath, // 起始目录
tr("Text Files (*.txt);;All Files (*)")); // 文件过滤器
//qDebug()<<"saveFile():"<<fileName;
if(!fileName.isEmpty())
{
saveFileByName(fileName);
}
}
else
{
saveFileByName(m_saveFileName);
}
}
void MainWindow::saveFileTo()
{
// qDebug()<<"saveFileTo()";
QString appFilePath = QCoreApplication::applicationDirPath();
QString fileName = QFileDialog::getSaveFileName(this, // 父窗口指针
tr("另存为文件"), // 对话框标题
appFilePath, // 起始目录
tr("Text Files (*.txt);;All Files (*)")); // 文件过滤器
//qDebug()<<"saveFile():"<<fileName;
if(!fileName.isEmpty())
{
saveFileByName(fileName);
}
}
void MainWindow::exitApp()
{
qDebug()<<"exitApp()";
//QApplication::quit();
this->close();
}
void MainWindow::textChangedSlots()
{
QString text = ui->textEdit->toPlainText().trimmed(); // 去除首尾空白字符
if (!text.isEmpty()) {
// 输入非空
m_fileIsSave = false;
}
}
// 保存最近文件列表到配置文件
void MainWindow::saveRecentFiles(const QString &newFile)
{
QSettings settings(m_iniName, QSettings::IniFormat);
// 2. 维护列表逻辑(去重、长度控制)
m_recentList.removeAll(newFile); // 删除已有条目(避免重复)
m_recentList.prepend(newFile); // 新文件插入最前面
if(m_recentList.size() > m_intFileCount)
{ // 限制最大数量(例如5个)
m_recentList.removeLast();
}
// 3. 写入配置
for(int i = 0;i < m_recentList.size();i++)
{
settings.setValue(m_iniLblName + m_keyPrefix + QString::number(i), m_recentList[i]);
}
settings.sync(); // 强制立即写入磁盘
}
void MainWindow::openFileByName(const QString &fileName)
{
// 打开文件的逻辑
//qDebug() << "打开文件:" << file;
QFile file(fileName);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
m_saveFileName = fileName;
//一次性全部读取
QByteArray fileAll = file.readAll();
ui->textEdit->setText(QString(fileAll));
//一行一行读取
// QString fileData = "";
// while (!in.atEnd()) {
// QString line = in.readLine();
// //qDebug() << line;
// fileData.append(line + "\r\n");
// }
// ui->textEdit->setText(fileData);
file.close();
m_fileIsSave = false;
this->setWindowTitle(fileName);
ui->statusbar->showMessage(fileName);
//saveHistoryFileListIni(m_keyPrefix+QString::number(m_iniKeyisEmptyInde),fileName);
saveRecentFiles(fileName); // 更新历史记录
initMenu(); // 刷新菜单显示
}
}
bool MainWindow::saveFileByName(const QString &fileName)
{
QFile file(fileName);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
// QTextStream out(&file);
// out << Qt::endl ; // 写入文本到文件
// file.close();
QByteArray ba;
ba.append(ui->textEdit->toPlainText().toUtf8());
file.write(ba);
file.close();
m_fileIsSave = true;
ui->statusbar->showMessage("保存成功."+fileName);
}
}