QT记事本

记事本应用程序提供了基本的文本编辑功能,支持文件的新建、打开、保存和另存为操作,同时具备修改提示和关闭窗口时的保存确认功能。使用 UTF - 8 编码确保了对多语言文本的支持。
在这里插入图片描述

1. 项目整体结构

  • main.cpp:程序的入口点,负责初始化 Qt 应用程序并创建Notepad窗口实例,最后进入应用程序的事件循环。
  • mainwindow.h:定义了Notepad类,继承自QMainWindow,包含了窗口的成员变量和成员函数的声明。
  • mainwindow.cpp:实现了Notepad类的成员函数,完成了记事本的各种功能。

2. 主要功能模块

2.1 窗口初始化
  • Notepad类的构造函数中,创建了一个QTextEdit控件作为中央部件,用于文本编辑。
  • 调用createActions()createMenus()函数创建菜单栏和菜单项对应的动作。
  • 设置窗口标题、大小和初始修改状态。
2.2 菜单栏和动作
  • 文件菜单 (文件(&F))
    • 新建 (&N) (Ctrl+N):调用newFile()函数,在保存当前修改后清空文本编辑区,重置当前文件名和修改状态。
    • 打开 (&O)… (Ctrl+O):调用openFile()函数,在保存当前修改后弹出文件选择对话框,选择文件并加载到文本编辑区。
    • 保存 (&S) (Ctrl+S):调用saveFile()函数,如果当前文件名为空,则调用saveAsFile()函数进行另存为操作;否则直接保存当前文件。
    • 另存为 (&A)… (Ctrl+Shift+S):调用saveAsFile()函数,弹出文件保存对话框,选择保存路径和文件名并保存文件。
    • 退出 (&X):调用QWidget::close()函数关闭窗口。
  • 帮助菜单 (帮助(&H))
    • 关于 (&A)…:调用about()函数,弹出关于对话框,显示应用程序的版本信息和开发环境。
2.3 文件操作
  • 保存文件 (save(const QString &fileName)):使用QSaveFile打开文件,以 UTF - 8 编码将文本编辑区的内容写入文件。如果保存成功,更新当前文件名和修改状态。
  • 加载文件 (loadFile(const QString &fileName)):使用QFile打开文件,自动检测文件编码并读取内容到文本编辑区。如果打开失败,弹出错误对话框。
2.4 修改提示
  • maybeSave():在新建文件、打开文件或关闭窗口时,检查文本编辑区的内容是否被修改。如果已修改,弹出警告对话框询问用户是否保存更改,根据用户的选择进行相应操作。
2.5 关闭窗口处理
  • closeEvent(QCloseEvent \*event):在窗口关闭时,调用maybeSave()函数询问用户是否保存更改。如果保存成功或用户选择不保存,则接受关闭事件;否则忽略关闭事件。

main.c

// main.cpp
#include "mainwindow.h"
#include <QApplication>int main(int argc ,char *argv[])
{QApplication app(argc, argv);app.setWindowIcon(QIcon(":/icons/notepad.png"));Notepad notepad;notepad.show();return app.exec();
}

mianwidow.c

// notepad.cpp
#include "mainwindow.h"
#include <QTextStream>
#include <QSaveFile>       // 添加缺失的头文件
#include <QStringConverter> // 添加缺失的头文件#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endifNotepad::Notepad(QWidget *parent): QMainWindow(parent),textEdit(new QTextEdit),fileMenu(nullptr),newAct(nullptr),openAct(nullptr),saveAct(nullptr),saveAsAct(nullptr),exitAct(nullptr),helpMenu(nullptr),aboutAct(nullptr)
{textEdit = new QTextEdit;setCentralWidget(textEdit);createActions();createMenus();setWindowTitle(QStringLiteral("Qt记事本[*]"));resize(800, 600);setWindowModified(false);
}void Notepad::createActions()
{newAct = new QAction(QStringLiteral("新建(&N)"), this);newAct->setShortcut(QKeySequence::New);connect(newAct, &QAction::triggered, this, &Notepad::newFile);openAct = new QAction(QStringLiteral("打开(&O)..."), this);openAct->setShortcut(QKeySequence::Open);connect(openAct, &QAction::triggered, this, &Notepad::openFile);saveAct = new QAction(QStringLiteral("保存(&S)"), this);saveAct->setShortcut(QKeySequence::Save);connect(saveAct, &QAction::triggered, this, &Notepad::saveFile);saveAsAct = new QAction(QStringLiteral("另存为(&A)..."), this);saveAsAct->setShortcut(QKeySequence::SaveAs);connect(saveAsAct, &QAction::triggered, this, &Notepad::saveAsFile);exitAct = new QAction(QStringLiteral("退出(&X)"), this);connect(exitAct, &QAction::triggered, this, &QWidget::close);aboutAct = new QAction(QStringLiteral("关于(&A)..."), this);connect(aboutAct, &QAction::triggered, this, &Notepad::about);
}void Notepad::createMenus()
{fileMenu = menuBar()->addMenu(QStringLiteral("文件(&F)"));fileMenu->addAction(newAct);fileMenu->addAction(openAct);fileMenu->addAction(saveAct);fileMenu->addAction(saveAsAct);fileMenu->addSeparator();fileMenu->addAction(exitAct);helpMenu = menuBar()->addMenu(QStringLiteral("帮助(&H)"));helpMenu->addAction(aboutAct);
}void Notepad::newFile()
{if (maybeSave()) {textEdit->clear();currentFile.clear();setWindowModified(false);}
}void Notepad::openFile()
{if (maybeSave()) {QString fileName = QFileDialog::getOpenFileName(this);if (!fileName.isEmpty()) {loadFile(fileName);setWindowModified(false);}}
}bool Notepad::saveFile()
{return currentFile.isEmpty() ? saveAsFile() : save(currentFile);
}bool Notepad::saveAsFile()  // 修正返回类型为bool
{QString fileName = QFileDialog::getSaveFileName(this,QStringLiteral("另存为"), currentFile);return fileName.isEmpty() ? false : save(fileName);
}
void Notepad::about()
{QMessageBox::about(this, QStringLiteral("关于 Qt记事本"),QStringLiteral("<h2>Qt记事本 2.0</h2>""<p>基于Qt 6.5开发</p>""<p>支持UTF-8编码文件读写</p>"));
}bool Notepad::maybeSave()
{if (!textEdit->document()->isModified())return true;QMessageBox::StandardButton ret = QMessageBox::warning(this,QStringLiteral("文档修改"),QStringLiteral("文档内容已修改,是否保存更改?"),QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);if (ret == QMessageBox::Save)return saveFile();else if (ret == QMessageBox::Cancel)return false;return true;
}bool Notepad::save(const QString &fileName)
{QSaveFile file(fileName);if (file.open(QFile::WriteOnly | QFile::Text)) {QTextStream out(&file);out.setEncoding(QStringConverter::Utf8);out << textEdit->toPlainText();if (file.commit()) {currentFile = fileName;setWindowModified(false);return true;}}QMessageBox::critical(this, QStringLiteral("保存失败"),QStringLiteral("无法保存文件:\n%1\n%2").arg(fileName, file.errorString()));return false;
}void Notepad::loadFile(const QString &fileName)
{QFile file(fileName);if (file.open(QFile::ReadOnly | QFile::Text)) {QTextStream in(&file);in.setAutoDetectUnicode(true);textEdit->setText(in.readAll());currentFile = fileName;} else {QMessageBox::critical(this, QStringLiteral("打开失败"),QStringLiteral("无法打开文件:\n%1\n%2").arg(fileName, file.errorString()));}
}void Notepad::closeEvent(QCloseEvent *event)
{maybeSave() ? event->accept() : event->ignore();
}Notepad::~Notepad() {}

一、核心功能实现分析

  1. 文件操作框架

    • 采用

      QSaveFile
      

      实现原子写入(先写临时文件再替换原文件),有效防止写入中断导致文件损坏;

    • loadFile()
      

      使用

      QTextStream
      

      自动检测编码,但建议增加手动编码选择功能(参考Notepad++的多编码支持);

    • 缺少最近文件列表功能,可参考Notepad++的Session机制

      实现历史文件恢复。

  2. 菜单系统架构

    • 采用经典MVC模式,通过QAction实现命令与UI解耦;
    • 快捷键绑定符合平台规范,但缺少自定义快捷键功能(Notepad++支持快捷键自定义)。
  3. 编码处理

    • 显式设置UTF-8编码(QStringConverter::Utf8),但未处理BOM标记;
    • 建议参考Notepad++的编码识别机制,添加自动检测编码功能。

二、潜在问题及改进建议

  1. 大文件处理

    • 当前实现直接读取整个文件到内存,存在内存耗尽风险。建议:

      复制

      // 分块读取(示例)
      while(!in.atEnd()) {QString chunk = in.read(4096);textEdit->insertPlainText(chunk);
      }
      
    • 可参考Notepad++的1MB缓存限制机制

  2. 安全漏洞预防

    • 未实现文件变更监控,建议添加QFileSystemWatcher检测外部修改;

    • 需注意Notepad++曾出现的编码转换漏洞

      ,建议对转换缓冲区进行边界检查。

  3. 用户体验优化

    • 增加多文档支持(参考Notepad++的Tab系统)

    • 实现撤销/重做栈:

      复制

      connect(textEdit->document(), &QTextDocument::undoAvailable, undoAct, &QAction::setEnabled);
      

三、关键代码段优化

  1. 编码处理增强

    复制

    // 改进后的保存函数
    bool Notepad::save(const QString &fileName) {QSaveFile file(fileName);if (file.open(QFile::WriteOnly | QFile::Text)) {QTextStream out(&file);// 添加BOM支持out.setGenerateByteOrderMark(true); out.setEncoding(QStringConverter::Utf8);// 分块写入const QString text = textEdit->toPlainText();for(int i=0; i<text.size(); i+=4096) {out << text.mid(i, 4096);}return file.commit();}//...错误处理
    }
    
  2. 会话管理实现

    // 参考Notepad++的Session结构[4](@ref)
    struct Session {QStringList recentFiles;QMap<QString, QByteArray> fileStates; // 文件路径+光标位置等
    };
    

四、架构扩展建议

  1. 插件系统设计

    • 创建PluginInterface抽象基类
    • 实现类似Notepad++的插件加载机制
  2. 语法高亮支持

    // 参考Scintilla库集成[2](@ref)
    class SyntaxHighlighter : public QSyntaxHighlighter {// 实现词法分析规则
    };
    

mianwindow.h

// notepad.h
#ifndef NOTEPAD_H
#define NOTEPAD_H#include <QMainWindow>
#include <QTextEdit>
#include <QFileDialog>
#include <QMessageBox>
#include <QCloseEvent>
#include <QTextStream>
#include <QMenuBar>       // 添加缺失的头文件
#include <QMenu>          // 添加缺失的头文件
#include <QAction>        // 添加缺失的头文件class Notepad : public QMainWindow
{Q_OBJECTpublic:explicit Notepad(QWidget *parent = nullptr);~Notepad();protected:void closeEvent(QCloseEvent *event) override;private slots:void newFile();void openFile();bool saveFile();       // 修正返回类型为boolbool saveAsFile();     // 修正返回类型为boolvoid about();private:void createActions();void createMenus();bool maybeSave();bool save(const QString &fileName);void loadFile(const QString &fileName);QTextEdit *textEdit;QString currentFile;QMenu *fileMenu;QAction *newAct;QAction *openAct;QAction *saveAct;QAction *saveAsAct;QAction *exitAct;QMenu *helpMenu;QAction *aboutAct;
};#endif // NOTEPAD_H

一、代码结构分析

  1. 继承关系

    cpp

    复制

    class Notepad : public QMainWindow
    
    • 符合Qt主窗口程序标准结构
    • 支持菜单栏、工具栏等标准组件
  2. 成员变量设计

    cpp

    复制

    QTextEdit *textEdit;       // 核心编辑组件
    QString currentFile;       // 当前文件路径
    QMenu *fileMenu, *helpMenu; // 主菜单项
    QAction *newAct, *openAct... // 功能动作
    
    • 采用Qt对象树内存管理机制
    • 指针初始化为nullptr(构造函数初始化列表可见)

二、接口设计评估

  1. 信号槽系统

    cpp

    复制

    private slots:void newFile();bool saveFile();  // 注意:Qt槽函数通常返回void
    
    • 存在设计矛盾:saveFile()返回bool但作为槽函数

    建议修改

    cpp

    复制

    private:bool performSave(); // 非槽函数
    private slots:void saveFile();    // 调用performSave()
    
  2. 事件处理

    cpp

    复制

    protected:void closeEvent(QCloseEvent *event) override;
    
    • 正确覆盖基类虚函数
    • 配合maybeSave()实现关闭确认

三、代码健壮性分析

  1. 头文件包含

    cpp

    复制

    #include <QMenuBar>  // 冗余包含
    
    • QMainWindow已包含QMenuBar

    优化建议

    cpp

    复制

    // 前置声明替代部分包含
    class QMenu;
    class QAction;
    
  2. 防御性编程

    cpp

    复制

    void createActions(); // 未处理可能的创建失败
    

    建议增强

    cpp

    复制

    bool createActions(); // 返回创建状态
    

四、扩展性改进建议

  1. 支持多编码

    cpp

    复制

    // 添加编码相关成员
    QTextCodec *currentCodec = QTextCodec::codecForName("UTF-8");
    
  2. 会话管理

    cpp

    复制

    // 添加最近文件列表
    QStringList recentFiles;
    static const int MAX_RECENT_FILES = 5;
    

五、代码规范优化

  1. 命名一致性

    cpp

    复制

    void about();  // 与"关于Qt"的常规命名不一致
    
    • 建议改为aboutQtNotepad()
  2. const正确性

    cpp

    复制

    bool save(const QString &fileName); 
    
    • 可添加const修饰:

      cpp

      复制

      bool isModified() const;
      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/41664.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何用 Postman 发送 POST 请求?

POST 请求是 HTTP 协议中用于提交数据的一种方法&#xff0c;Postman 提供了丰富的功能来支持用户发送包含各种信息的 POST 请求&#xff0c;如文本数据、JSON 或 XML 数据结构、文件等。 Postman 发送 post 请求教程

Ant Design Vue 中的table表格高度塌陷,造成行与行不齐的问题

前言&#xff1a; Ant Design Vue: 1.7.2 Vue2 less 问题描述&#xff1a; 在通过下拉框选择之后&#xff0c;在获取接口数据&#xff0c;第一列使用了fixed:left&#xff0c;就碰到了高度塌陷&#xff0c;查看元素的样式结果高度不一致&#xff0c;如&#x…

Flink 通过 Chunjun Oracle LogMiner 实时读取 Oracle 变更日志并写入 Doris 的方案

文章目录 一、 技术背景二、 关键技术1、 Oracle LogMiner2、 Chunjun 的 LogMiner 关键流程3、修复 Chunjun Oracle LogMiner 问题 一、 技术背景 在大数据实时同步场景中&#xff0c;需要将 Oracle 数据库的变更数据&#xff08;CDC&#xff09; 采集并写入 Apache Doris&am…

qt+opengl 加载三维obj文件

1前面我们已经熟悉了opengl自定义顶点生成一个立方体&#xff0c;并且我们实现了立方体的旋转&#xff0c;光照等功能。下面我们来用opengl来加载一个obj文件。准备我们首先准备一个简单的obj文件&#xff08;head.obj&#xff09;。资源在本页下载 2 在obj文件里面&#xff0c…

计算机组成原理的学习day01

一 计算机系统层次结构 1 计算机硬件的基本组成 好的&#xff0c;上个小节中我们了解了计算机系统的概念&#xff0c;还有计算机的一个发展历程&#xff0c;那这个小节中我们会着重的探讨计算机硬件的一个基本组成。我们需要掌握这样的两种结构&#xff0c;第一种是早期的冯诺…

ASP 应用HTTP.SYS短文件文件解析Access 注入数据库泄漏

#ASP- 默认安装 -MDB 数据库泄漏下载&#xff08;路径是知道的话可以直接下载&#xff09; 由于大部分 ASP 程序与 ACCESS 数据库搭建&#xff0c;但 ACCESS 无需连接&#xff0c;都在脚本文件中定 义配置好数据库路径即用&#xff0c;不需要额外配置安装数据库&#x…

Redis 版本演进及主要新特性

Redis 版本发布历史 稳定版本时间线 Redis 2.6 (2012年)Redis 2.8 (2013年11月)Redis 3.0 (2015年4月) - 首次支持集群Redis 3.2 (2016年5月)Redis 4.0 (2017年7月)Redis 5.0 (2018年10月)Redis 6.0 (2020年4月)Redis 6.2 (2021年2月)Redis 7.0 (2022年4月) - 最新稳定版(截至…

从 MySQL 到时序数据库 TDengine:Zendure 如何实现高效储能数据管理?

小T导读&#xff1a;TDengine 助力广州疆海科技有限公司高效完成储能业务的数据分析任务&#xff0c;轻松应对海量功率、电能及输入输出数据的实时统计与分析&#xff0c;并以接近 1 : 20 的数据文件压缩率大幅降低存储成本。此外&#xff0c;taosX 强大的 transform 功能帮助用…

NVM安装速通使用手册(Windows版)NVM管理node版本命令手册 NVM使用手册

nvm&#xff08;Node Version Manager&#xff09;是一个用于管理Node.js版本的命令行工具。通过nvm&#xff0c;你可以在同一台机器上安装和切换多个Node.js版本&#xff0c;非常适合开发和测试在不同Node.js版本上运行的应用程序 一、安装地址 1. 官方下载&#xff1a; &…

qt QQuaternion详解

1. 概述 QQuaternion 是 Qt 中用于表示三维空间中旋转的四元数类。它包含一个标量部分和一个三维向量部分&#xff0c;可以用来表示旋转操作。四元数在计算机图形学中广泛用于平滑的旋转和插值。 2. 重要方法 默认构造函数 QQuaternion::QQuaternion(); // 构造单位四元数 (1…

Axure项目实战:智慧城市APP(四)医疗信息(动态面板、选中交互应用)

亲爱的小伙伴&#xff0c;在您浏览之前&#xff0c;烦请关注一下&#xff0c;在此深表感谢&#xff01; 课程主题&#xff1a;智慧城市APP医疗信息模块 主要内容&#xff1a;医疗信息模块原型设计与交互 应用场景&#xff1a;医疗信息行业 案例展示&#xff1a; 案例视频&…

DeepSeek助力文案,智能音箱如何改变你的生活?

你好&#xff0c;我是三桥君 你有没有为写智能音箱的宣传文案而抓耳挠腮过&#xff1f;三桥君在这方面可是有些感想&#xff0c;今天就来给你唠唠怎么用DeepSeek写出超赞的智能音箱宣传文案。 首先&#xff0c;你得给DeepSeek喂足“料”。这就好比做饭&#xff0c;你得准备好各…

二叉树的前,中,后序遍历

我们来了解一下二叉树的遍历&#xff0c;话不多说 二叉树的遍历的概念&#xff1a; 二叉树有四种遍历方式&#xff0c;分别为前序遍历&#xff0c;中序遍历&#xff0c;后序遍历和层序遍历&#xff0c;但我们今天谈谈前三种&#xff0c;并实现它 前序遍历&#xff1a; 按照根…

Linux网站搭建(新手必看)

1.宝塔Linux面板的功能 宝塔面板是一款服务器管理软件&#xff0c;可以帮助用户建立网站&#xff0c;一键配置服务器环境&#xff0c;使得用户通过web界面就可以轻松的管理安装所用的服务器软件。 2. 宝塔Linux面板的安装 宝塔官网地址&#xff1a;宝塔面板 - 简单好用的Linu…

secp256k1的模数P是如何选择的?

在区块链和现代密码学中&#xff0c;secp256k1 椭圆曲线以其高安全性和高效运算性能而著称。你可能注意到&#xff0c;secp256k1 的曲线方程为 而其中的模数 p 被定义为 那么&#xff0c;为何会选择这样一个看似复杂的数呢&#xff1f;本文将从多个角度为你详细解析这一选择背后…

本地文生图使用插件(Stable Diffusion)

1. 插件下载&#xff08;github&#xff09; 1.1 直接Avaliable中点击安装&#xff08;方案一&#xff09; 1.2 Install from URL中输入URL&#xff08;方案二&#xff09; 1.3 直接下载复制到extensions目录&#xff08;方案三&#xff09; 2. 模型下载&#xff08;Huggingf…

鸿蒙-全屏播放页面(使用相对布局)---持续更新中

最终实现效果图&#xff1a; 实现步骤 创建FullScreenPlay.ets全品播放页面 并将其修改为启动页面。 全屏播放&#xff0c;屏幕必然横过来&#xff0c;所以要将窗口横过来。 编辑 src/main/ets/entryability/EntryAbility.ets 若写在/EntryAbility.ets中&#xff0c;则所有…

C++ 多线程简要讲解

std::thread是 C11 标准库中用于多线程编程的核心类&#xff0c;提供线程的创建、管理和同步功能。下面我们一一讲解。 一.构造函数 官网的构造函数如下&#xff1a; 1.默认构造函数和线程创建 thread() noexcept; 作用&#xff1a;创建一个 std::thread 对象&#xff0c;但…

每天认识一个设计模式-建造者模式:复杂对象的“装配式革命“

一、前言 在软件开发的广袤领域中&#xff0c;随着项目规模日益庞大、业务逻辑愈发复杂&#xff0c;对象的创建过程也变得千头万绪。 早期简单的对象创建方式&#xff0c;在面对复杂对象时&#xff0c;逐渐显露出代码臃肿、耦合度高、可维护性差等弊端&#xff0c;设计模式的…

动态IP与静态IP该如何选?

一、当IP地址成为"网络身份" 2023年亚马逊封号潮中&#xff0c;某杭州卖家因登录IP频繁切换&#xff08;早8点在纽约&#xff0c;午间瞬移到东京&#xff09;&#xff0c;触发平台风控导致账号冻结。这类"时空错乱症"揭示了跨境电商的生存法则&#xff1a…