java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java记事本

Java实现简单记事本的完整指南

作者:bug菌

做一个小工具,看似不起眼,但在开发过程中,却时常被一些“细节”所困扰,本文将记录使用Java语言编写记事本的完整步骤,希望对大家有所帮助

前言

有时候,灵感就像一阵风,突然间吹过,你无法预料它的到来,只能尽快抓住。这次,我突然想做一个类似 TXT 记事本的小工具。你没听错,就是那个每天记录生活琐事、随便写写的记事本。听起来简单对吧?“只要放个文本框,写个菜单,怎么都能完成。”但要我说,这个简单的“记事本”背后却有着不为人知的思考与细节。每一行代码,都是我多年来在开发过程中忽视的Java基础,甚至每一个微小的优化,都在体现我对该门开发语言背后的一次重新认识。

做一个小工具,看似不起眼,但在开发过程中,我却时常被这些“细节”所困扰。每次碰到挑战,哪怕是一个看似简单的需求,都让我忍不住嘴角微翘:这不仅是撸代码的挑战,更是对自己技术基础的一次重新审视。而这个简易的记事本,居然成了我对“编码”这门艺术的一次深刻打磨(还好底子够厚)。

技术点概述

在这个小项目中,我结合了这两项技术,用它们来构建这个简易的记事本应用。表面看,它只是一个简单的记事本,但对我来说,它代表了我多年来对编程技术的理解与提升。

1. 项目需求分析

很多人看见记事本时,可能觉得“这不就是个简单的文本框吗?”的确,它是个文本框,但背后涉及到的细节可不止这些。我的目标是做一个 简洁、高效、易用 的记事本工具,它不只让你“写”字,还让你能愉快地操作、管理文件。为此,我设计了以下几个功能:

这些看似简单的需求,其实背后涉及到很多细节和优化。比如,字体选择功能,我并没有仅仅实现一个下拉框,而是让用户能轻松预览字体效果;又比如在保存文件时,我对文件路径做了自动判断,确保用户不会保存到错误的位置。每个细节都是我对用户体验的精雕细琢。

2. Java Swing 简介

在我多年的开发经历中,Java Swing 见证了我从初学者到有一定开发经验的过程。最开始,我对 Swing 充满了恐惧。各种布局、组件、事件监听等概念让我头晕目眩,特别是在布局管理器的使用上,我从未想过有那么多种不同的布局方式,每种方式的使用场景也让我感到困惑。然而,随着时间的推移,我逐渐理解了它们的设计思路,掌握了如何利用这些组件和布局来实现我想要的界面效果。

最初,我花了很多时间调试界面组件,尤其是 JTextArea 和 JScrollPane 的配合。每次调整窗口大小时,文本框内容的显示问题就会让我抓狂。于是我开始慢慢理解:布局并不是单纯地“摆放控件”,而是要让每一个控件都能在不同尺寸的窗口中自如适应,确保它们之间的互动更自然。

经过无数次的尝试与调整,我终于学会了用 Swing 设计简洁、流畅的桌面应用。每次看到界面稳定运行时,那种满足感让我觉得:这份辛苦是值得的。

常用组件介绍:

3. 项目实现

一开始,我的目标是简单地搭建一个基本的界面,能让用户输入文本、保存文件、设置字体等。但随着需求的不断丰富,我发现每一步都需要不断优化代码,解决隐藏的问题。例如,在文件保存时,我不得不考虑编码问题、路径问题、扩展名问题等,甚至在用户关闭应用时,我都要细心处理文件未保存的情况。

3.1 代码演示

首先,我们创建一个基本的窗口框架,其中包含一个文本编辑区域和菜单栏。然后,我们会逐步实现文件操作功能。具体代码如下演示,仅供参考:

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @date: 2025-07-31 15:56
 */
public class NotepadApp {
    private JFrame frame;
    private JTextArea textArea;
    private JFileChooser fileChooser;
    private String currentFilePath = null; // 当前文件路径
    private JLabel statusLabel;           // 状态栏标签
    private UndoManager undoManager;      // 撤销/重做管理器

    public NotepadApp() {
        frame = new JFrame("简易记事本");
        textArea = new JTextArea();
        fileChooser = new JFileChooser();
        undoManager = new UndoManager();

        // 设置基本布局
        frame.setLayout(new BorderLayout());
        frame.add(new JScrollPane(textArea), BorderLayout.CENTER);

        // 设置文本区
        textArea.setFont(new Font("Serif", Font.PLAIN, 14)); // 默认字体
        textArea.setLineWrap(true); // 自动换行
        textArea.setWrapStyleWord(true); // 按字换行
        textArea.getDocument().addUndoableEditListener(e -> undoManager.addEdit(e.getEdit())); // 撤销/重做监听

        // 状态栏
        statusLabel = new JLabel("  未保存  ");
        frame.add(statusLabel, BorderLayout.SOUTH); // 状态栏显示

        // 创建菜单栏
        JMenuBar menuBar = new JMenuBar();
        frame.setJMenuBar(menuBar);
        createMenu(menuBar);

        // 设置窗口
        frame.setSize(600, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null); // 居中显示

        // 设置图标
        ImageIcon icon = new ImageIcon("notepad_icon.png"); // 添加图标
        frame.setIconImage(icon.getImage());
    }

    // 创建菜单
    private void createMenu(JMenuBar menuBar) {
        JMenu fileMenu = new JMenu("文件");
        JMenu editMenu = new JMenu("编辑");

        // 文件菜单项
        JMenuItem openItem = new JMenuItem("打开");
        openItem.addActionListener(e -> openFile());
        fileMenu.add(openItem);

        JMenuItem saveItem = new JMenuItem("保存");
        saveItem.addActionListener(e -> saveFile());
        fileMenu.add(saveItem);

        JMenuItem saveAsItem = new JMenuItem("另存为");
        saveAsItem.addActionListener(e -> saveFileAs());
        fileMenu.add(saveAsItem);

        JMenuItem exitItem = new JMenuItem("退出");
        exitItem.addActionListener(e -> exitApplication());
        fileMenu.add(exitItem);

        // 编辑菜单项
        JMenuItem undoItem = new JMenuItem("撤销");
        undoItem.addActionListener(e -> undoAction());
        editMenu.add(undoItem);

        JMenuItem redoItem = new JMenuItem("重做");
        redoItem.addActionListener(e -> redoAction());
        editMenu.add(redoItem);

        JMenuItem fontItem = new JMenuItem("字体样式");
        fontItem.addActionListener(e -> changeFont());
        editMenu.add(fontItem);

        // 将菜单添加到菜单栏
        menuBar.add(fileMenu);
        menuBar.add(editMenu);
    }

    // 打开文件
    private void openFile() {
        int returnValue = fileChooser.showOpenDialog(frame);
        if (returnValue == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            try {
                currentFilePath = selectedFile.getAbsolutePath();
                String content = new String(Files.readAllBytes(selectedFile.toPath()), StandardCharsets.UTF_8); // UTF-8 编码读取
                textArea.setText(content);
                statusLabel.setText("  已打开: " + currentFilePath);
            } catch (IOException e) {
                showError("无法打开文件");
            }
        }
    }

    // 保存文件
    private void saveFile() {
        if (currentFilePath == null) {
            saveFileAs();
        } else {
            try {
                Files.write(Paths.get(currentFilePath), textArea.getText().getBytes(StandardCharsets.UTF_8)); // UTF-8 编码保存
                statusLabel.setText("  已保存: " + currentFilePath);
            } catch (IOException e) {
                showError("保存文件失败");
            }
        }
    }

    // 另存为
    private void saveFileAs() {
        int returnValue = fileChooser.showSaveDialog(frame);
        if (returnValue == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            currentFilePath = selectedFile.getAbsolutePath();
            if (!currentFilePath.endsWith(".txt")) {
                currentFilePath += ".txt"; // 自动加上 .txt 扩展名
            }
            saveFile();
        }
    }

    // 改变字体
    private void changeFont() {
        String[] fonts = {"Serif", "Arial", "Verdana"};
        String selectedFont = (String) JOptionPane.showInputDialog(frame,
                "选择字体",
                "字体样式",
                JOptionPane.PLAIN_MESSAGE,
                null,
                fonts,
                fonts[0]);
        if (selectedFont != null) {
            String[] sizes = {"12", "14", "16", "18", "20"};
            String selectedSize = (String) JOptionPane.showInputDialog(frame,
                    "选择字号",
                    "字号",
                    JOptionPane.PLAIN_MESSAGE,
                    null,
                    sizes,
                    sizes[1]);
            if (selectedSize != null) {
                textArea.setFont(new Font(selectedFont, Font.PLAIN, Integer.parseInt(selectedSize)));
            }
        }
    }

    // 撤销
    private void undoAction() {
        if (undoManager.canUndo()) {
            undoManager.undo();
        }
    }

    // 重做
    private void redoAction() {
        if (undoManager.canRedo()) {
            undoManager.redo();
        }
    }

    // 退出应用程序
    private void exitApplication() {
        if (confirmExit()) {
            System.exit(0);
        }
    }

    // 弹窗提示是否保存文件
    private boolean confirmExit() {
        int response = JOptionPane.showConfirmDialog(frame,
                "是否保存文件?",
                "退出",
                JOptionPane.YES_NO_CANCEL_OPTION,
                JOptionPane.QUESTION_MESSAGE);
        if (response == JOptionPane.YES_OPTION) {
            saveFile();
            return true;
        } else if (response == JOptionPane.NO_OPTION) {
            return true;
        }
        return false;
    }

    // 显示错误信息
    private void showError(String message) {
        JOptionPane.showMessageDialog(frame, message, "错误", JOptionPane.ERROR_MESSAGE);
    }

    // 启动应用程序
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            NotepadApp app = new NotepadApp();
            app.frame.setVisible(true);
        });
    }
}

3.2 代码解析

代码的核心部分主要包括界面设计、文件操作、字体选择和撤销重做等功能的实现。每个功能我都逐步进行了实现,并在每个环节中进行细致优化。例如,在 文件操作 部分,我采用了 Files.readAllBytes() 和 Files.write() 来保证文件操作的高效与安全;在 字体选择 部分,我通过弹窗让用户可以自由选择字体和字号,并实时预览效果。

这个小小的记事本,虽然看起来简单,但每一行代码都承载着我对编程的热爱与执着。从每个细节的实现中,我不断打磨自己的技术,精益求精。

1. 类成员变量

2. 构造函数:初始化界面和控件

主要步骤:

状态栏:

菜单栏:

3. 文件操作功能

打开文件 (openFile()):

保存文件 (saveFile()):

另存为 (saveFileAs()):

4. 文本编辑功能

改变字体 (changeFont())

撤销和重做 (undoAction() 和 redoAction())

5. 退出应用程序与保存提示

退出应用程序 (exitApplication()):

确认保存 (confirmExit()):

6. 错误提示

显示错误信息 (showError()):

使用 JOptionPane.showMessageDialog() 弹出一个错误提示框,显示错误信息(如文件无法打开或保存失败)。

7. 启动应用程序

启动应用程序 (main()):

3.3 主要功能

编辑文本

打开文件

保存文件

字体样式和字号选择

文件另存为

保存提示

编辑文本

用户可以在主界面的文本区域 (JTextArea) 中直接输入、修改和删除文本内容,支持基本的文本操作和自动换行,适合快速记录笔记或编写文档。

撤销 / 重做: 支持对文本操作进行撤销和重做。

字体样式设置

用户可通过菜单选择字体名称(如 Serif、Arial、Verdana)和字号(如 12、14、16、18、20),即时应用于文本内容,改善阅读或编辑体验。

状态栏提示

窗口底部的状态栏动态显示当前文件的保存状态和路径,便于用户确认文件是否保存。

3.4 流程图

以下是记事本程序的基本流程图,为大家展示了用户如何通过菜单操作实现文件的打开、保存、字体选择等功能:

3.5 本地运行演示

当我看到记事本应用流畅运行时,内心的成就感是无可比拟的。每一项功能的实现,都让我回想起过去在编程中的学习和成长。虽然这只是一个简单的工具,但它象征着我多年来对技术的理解和沉淀。每一次的进步,都是我不断挑战自我的结果。

完整界面

如下是程序运行成功会自动弹出的一个界面,演示如下:

首先,点击【文件】可支持以下功能:打开、保存、另存为、退出。

【点击】编辑可支持的功能有:撤销、重做、字体样式。

打开文件

接着,我们来演示下打开文件:

接着我们任意打开一个文件,可对比我们本地的TXT记事本。

虽然功能上没有txt记事本丰富,但是,纯手搓的,是不是非常可以了!只需要把这些其他的功能逐步完善,那堪比记事本,甚至可谈超越。

保存文件

我们直接通过打开的文本进行新增内容,效果如下:

另存为

我们同样也可以将文件另存为,功能上与文件另存为毫无区别。

剩下的其他功能及未实现的功能点,这就留给大家去测试及完善啦,基础的模型已经替大家搭建好了。

4. 总结

通过本项目的实现,我们成功构建了一个简易的记事本应用,支持 文本编辑、文件打开、保存、另存为,并且实现了 字体选择、字号设置、保存提示 等功能。通过使用 Java Swing 和 Java IO,我们实现了图形界面的搭建和文件的读取写入。

通过这个记事本项目,大家不仅可以学会如何使用 Swing 开发桌面应用,还能深入了解了文件操作的基本方式。同时希望,大家可以在此基础上继续扩展功能,考虑加入 文本搜索、撤销重做文件加密保护 等功能,进一步提升应用的实用性和安全性。

我相信,编程不止是一个解决问题的工具,它更是一种创造和表达的方式。每一次的编程经历,都是对自己的一次磨砺,让我不断突破,不断成长。

到此这篇关于Java实现简单记事本的完整指南的文章就介绍到这了,更多相关Java记事本内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文