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

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);
    }
}


http://www.kler.cn/a/570518.html

相关文章:

  • RHCE9.0版本笔记3:创建、查看和编辑文本文件
  • Spark核心之03写mysql、写HBase、RDD宽窄依赖、DAG、缓存、Checkpoint
  • GSMA SAS 安全生产审计检查清单
  • ARM MTE
  • C++:类和对象(下篇)
  • 内网穿透的应用-企业级远程办公方案:NAS部署网页版Linux,HTTPS加密访问全配置
  • 【word】电子签名设置、保存和调用
  • 蓝桥杯 之 图形规律
  • 算法进阶——二分
  • 美团面试题解析:new Integer(“127“)和Integer.valueOf(“128“) 的底层差异与缓存机制
  • Java【多线程】(2)线程属性与线程安全
  • 前端-css
  • 物联网中水位计顶级功能有哪些
  • Muduo + OpenSSL 网络交互完整流程
  • 如何在MacOS 10.15上安装Docker Desktop
  • 数据结构(三)链表
  • 使用 CodeMirror 6 和 React 构建一个支持只读模式的 JSON 编辑器
  • 基于QSSH开源库实现SSH远程连接和SFTP文件传输
  • DeepSeek集成到VScode工具,让编程更高效
  • 玩转python: 几个案例-掌握贪心算法