首页 > 其他分享 >使用Swing创建一个简易文本编辑器

使用Swing创建一个简易文本编辑器

时间:2024-09-09 15:25:33浏览次数:13  
标签:文本编辑 菜单 void JMenuItem mainTextArea 简易 add Swing new

目录

1. 项目背景

2. 技术栈

3. 项目结构

3.1 EditFrame类

3.1.1 界面布局

3.1.2 功能实现

3.2 JEditMain类

3.2.1 使用SwingUtilities.invokeAndWait()

4. 代码示例


最近在学习Swing GUI编程时,尝试着自己动手实现了一个简易的文本编辑器。通过这个项目,我不仅加深了对Swing组件的理解,还学会了如何组织代码结构以及如何处理各种事件。下面我将分享一下我的实践过程和代码实现。

1. 项目背景

文本编辑器是计算机软件中的基础工具之一,对于学习编程的人来说,制作一个简单的文本编辑器是一个很好的练习项目。它可以帮助我们熟悉基本的图形用户界面设计,同时也能够让我们掌握文件读写的基本操作。

2. 技术栈

  • Java SE
  • Swing

3. 项目结构

项目主要分为两个部分:EditFrame 类和 JEditMain 类。EditFrame 类负责整个编辑器界面的设计与逻辑处理;而 JEditMain 类则是项目的入口点,用于启动编辑器。

3.1 EditFrame类

EditFrame 类继承自 JFrame,用于创建一个窗口,并在这个窗口内添加文本区域、菜单栏和上下文菜单。此外,该类还包括了一些辅助方法,如创建菜单项、显示文件打开/保存对话框等。

3.1.1 界面布局

编辑器的主界面包含一个文本区域,用户可以在其中输入文本。同时,我们为它添加了一个滚动条以便于查看长文档。此外,还有菜单栏提供了文件操作选项(如打开、保存、退出等),以及编辑选项(如复制、粘贴、查找替换等)。为了方便用户操作,我们还为文本区域添加了一个上下文菜单,当用户右击文本区域时,会弹出一个包含常用编辑命令的小菜单。

如上图所示,这是我们的编辑器主界面。可以看到顶部的菜单栏包含了文件(File)、编辑(Edit)和帮助(Help)三个主菜单,右侧的滚动条可以帮助浏览长文档。

3.1.2 功能实现
  • 文件操作:支持文件的打开、保存及另存为。
  • 编辑功能:支持文本的复制、粘贴、剪切及查找替换。
  • 帮助信息:提供简单帮助和关于信息。

3.2 JEditMain类

JEditMain 类是程序的入口点,它包含了 main 方法。在这个类中,我们首先设置了系统的默认外观和感觉,然后调用 createGUI 方法来创建并显示我们的编辑器界面。

3.2.1 使用SwingUtilities.invokeAndWait()

由于Swing组件必须在事件调度线程(Event Dispatch Thread)上创建和更新,因此我们在 main 方法中使用了 SwingUtilities.invokeAndWait() 方法来确保我们的GUI创建代码在正确的线程上执行。

4. 源代码

以下是关键代码片段:

package com.xiaoqi.java;

import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.*;
import java.util.HashMap;

import static javax.swing.JOptionPane.PLAIN_MESSAGE;


public class EditFrame extends JFrame {
    private JTextArea mainTextArea;//文本域
    private Font font = new Font("微软雅黑", Font.PLAIN, 12);//字体对象

    //卷曲面板
    private JScrollPane jScrollPane;

    //全局事件监听器
    private ActionMenuItemListener actionMenuItemListener = new ActionMenuItemListener();

    //我也不知道我为什么要定义全局指向,应为tm的内部类要使用父类
    private Component globalThis = this;

    //弹出菜单
    private JPopupMenu mainPopupMenu;



    public EditFrame(String title) throws HeadlessException {
        super(title);

        //获取布局容器
        Container mainContentPane = getContentPane();
        mainContentPane.setLayout(new BorderLayout());

        //创建菜单
        createMenuToMainFrame(mainContentPane);

        //创建文本域
        createTexTMain(mainContentPane);

        //创建弹出菜单
        createPopMenu(mainContentPane,mainTextArea);

    }

    /**
     * @Description 创建右键菜单
     * @param mainContentPan
     * @param mainTextArea
     * @return void
     */
    private void createPopMenu(Container mainContentPan,JTextArea mainTextArea){
        //创建菜单
        mainPopupMenu = new JPopupMenu();
        JMenuItem copy = createMenuItem("复制", "copy");
        JMenuItem paste = createMenuItem("粘贴", "paste");
        JMenuItem repalce = createMenuItem("查找替换", "repalce");
        JMenuItem cut = createMenuItem("剪切", "cut");

        mainPopupMenu.add(copy);
        mainPopupMenu.add(paste);
        mainPopupMenu.addSeparator();
        mainPopupMenu.add(repalce);
        mainPopupMenu.addSeparator();
        mainPopupMenu.add(cut);

        //添加事件
        copy.addActionListener(actionMenuItemListener);
        paste.addActionListener(actionMenuItemListener);
        repalce.addActionListener(actionMenuItemListener);
        cut.addActionListener(actionMenuItemListener);


        //添加菜单弹出事件
        mainTextArea.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                //判断鼠标右键点击
                if (e.getButton() == MouseEvent.BUTTON3){
                    mainPopupMenu.show(e.getComponent(),e.getX(),e.getY());
                }
            }
        });

    }

    /**
     * @param mainContentPan
     * @return void
     * @Description 创建文本域
     */
    private void createTexTMain(Container mainContentPan) {
        mainTextArea = new JTextArea();
        mainTextArea.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); //设置鼠标在文本域的样式
        mainTextArea.setLineWrap(true);//自动换行
        mainTextArea.setFont(font);//设置文本域全局字体
        mainTextArea.setDisabledTextColor(Color.BLACK);

        //使用JScrollPan才有滚动条
        jScrollPane = new JScrollPane();
        mainContentPan.add(jScrollPane, BorderLayout.CENTER);
        jScrollPane.setViewportView(mainTextArea);

//        mainContentPan.add(mainTextArea);
    }

    /**
     * @param mainContentPane
     * @return void
     * @Description 创建菜单
     */
    private void createMenuToMainFrame(Container mainContentPane) {

        //创建菜单
        JMenuBar mainMenuBar = new JMenuBar();
        setJMenuBar(mainMenuBar);

        //创建文件菜单
        JMenu fileMenu = new JMenu("文件(file)");
        mainMenuBar.add(fileMenu);

        //创建子菜单
        JMenuItem openFile = createMenuItem("打开     (open)", "open");
        JMenuItem saveFile = createMenuItem("保存     (save)", "save");
        JMenuItem savaAs = createMenuItem("另存为   (save as)", "saveAs");
        JMenuItem exit = createMenuItem("退出     (Exit)", "exit");

        fileMenu.add(openFile);
        fileMenu.add(saveFile);
        fileMenu.add(savaAs);
        fileMenu.addSeparator();
        fileMenu.add(exit);

        //添加菜单事件
        openFile.addActionListener(actionMenuItemListener);
        saveFile.addActionListener(actionMenuItemListener);
        savaAs.addActionListener(actionMenuItemListener);
        exit.addActionListener(actionMenuItemListener);

        //创建编辑菜单
        JMenu editMrnu = new JMenu("编辑(edit)");
        JMenuItem copy = createMenuItem("复制(copy)", "copy");
        JMenuItem paste = createMenuItem("粘贴(paste)", "paste");
        JMenuItem repalce = createMenuItem("查找替换(replace)", "repalce");
        JMenuItem cut = createMenuItem("剪切(cut)", "cut");

        editMrnu.add(copy);
        editMrnu.add(paste);
        editMrnu.addSeparator();
        editMrnu.add(repalce);
        editMrnu.addSeparator();
        editMrnu.add(cut);

        mainMenuBar.add(editMrnu);

        //添加事件
        copy.addActionListener(actionMenuItemListener);
        paste.addActionListener(actionMenuItemListener);
        repalce.addActionListener(actionMenuItemListener);
        cut.addActionListener(actionMenuItemListener);



        //创建帮助菜单
        JMenu helpMenu = new JMenu("帮助(help)");
        mainMenuBar.add(helpMenu);

        //创建子菜单
        JMenuItem help = createMenuItem("帮助 (help)", "help");
        JMenuItem about = createMenuItem("关于 (about)", "about");

        helpMenu.add(help);
        helpMenu.addSeparator();
        helpMenu.add(about);

        //添加子菜单事件
        help.addActionListener(actionMenuItemListener);
        about.addActionListener(actionMenuItemListener);

    }

    /**
     * @param title
     * @param command
     * @return javax.swing.JMenuItem
     * @Description 创建子菜单项
     */
    private JMenuItem createMenuItem(String title, String command) {
        JMenuItem item = new JMenuItem(title);
        item.setActionCommand(command);
//        item.setFont(font);
        return item;
    }

    private class ActionMenuItemListener implements ActionListener {

        /**
         * @Description 事件分发
         * @param e
         * @return void
         */
        @Override
        public void actionPerformed(ActionEvent e) {

            //子菜单标识
            String actionCommand = e.getActionCommand();
            System.out.println(actionCommand);

            if (actionCommand.equals("save")){
                showSaveWindow(globalThis);
            }else if (actionCommand.equals("open")){
                showOpenWindow(globalThis);
            }else if (actionCommand.equals("saveAs")){
                showSaveWindow(globalThis);
            }else if (actionCommand.equals("exit")){
                System.exit(0);
            }else if (actionCommand.equals("help") || actionCommand.equals("about")){
                JOptionPane.showMessageDialog(globalThis,"欢迎使用记事本","提示:", PLAIN_MESSAGE);
            }else if (actionCommand.equals("copy")){
                mainTextArea.copy();
            }else if (actionCommand.equals("paste")){
                mainTextArea.paste();
            }else if (actionCommand.equals("repalce")){

                HashMap<String, String> replaceStringHashMap = createReplaceD();
                if (null != replaceStringHashMap) {
                    String mainTextAreaText = mainTextArea.getText();
                    String replaceAllString = mainTextAreaText.replaceAll(replaceStringHashMap.get("src"), replaceStringHashMap.get("rep"));
                    mainTextArea.setText(replaceAllString);
                }
            }else if (actionCommand.equals("cut")){
                mainTextArea.cut();
            }
        }

        /**
         * @Description 弹出输入框获取替换字符
         * @param
         * @return java.lang.String
         */
        private HashMap<String, String> createReplaceD(){
            String inputValue = JOptionPane.showInputDialog(globalThis, "输入要替换的文本: 被替换的文本/替换文本", "提示:", PLAIN_MESSAGE);
            if ("".equals(inputValue) || inputValue.isEmpty()) return null;
            String[] split = inputValue.split("/");
            HashMap<String, String> repalceStringHashMap = new HashMap<>();
            if (split.length != 2){
                return null;
            }
            repalceStringHashMap.put("src",split[0]);
            repalceStringHashMap.put("rep",split[1]);
            return repalceStringHashMap;
        }


        /**
         * @Description 打开选着文件对话框
         * @param This
         * @return void
         */
        public void showOpenWindow(Component This){
            //创建文件选着框
            JFileChooser selectFileChooser = new JFileChooser();

            //创建文件过滤器并设置到文件选则框
            FileNameExtensionFilter fileNameExtensionFilter = new FileNameExtensionFilter("文本文件", "txt", "java", "js", "html", "json", "xml", "ini", "conf","md");
            selectFileChooser.setFileFilter(fileNameExtensionFilter);

            //获取状态码
            int selectStatus = selectFileChooser.showOpenDialog(This);

            if (selectStatus == JFileChooser.APPROVE_OPTION){
                File selectedFile = selectFileChooser.getSelectedFile();
                //读入文件到全局文本域
                readFileToAreaText(selectedFile.getAbsolutePath(),mainTextArea);
            }

        }

        /**
         * @Description 打开保存文件对话框
         * @param This
         * @return void
         */
        private void showSaveWindow(Component This){

            //创建文件选着框
            JFileChooser saveFileChooser = new JFileChooser();

            //创建文件过滤器并设置到文件选则框
            FileNameExtensionFilter fileNameExtensionFilter = new FileNameExtensionFilter("文本文件", "txt", "java", "js", "html", "json", "xml", "ini", "conf","md");
            saveFileChooser.setFileFilter(fileNameExtensionFilter);

            int openStatus = saveFileChooser.showSaveDialog(This);

            if (openStatus == JFileChooser.APPROVE_OPTION){
                //获取文件的绝对路径写出文件
                File selectedFile = saveFileChooser.getSelectedFile();
                writeFile(selectedFile.getAbsolutePath(),mainTextArea);
            }
        }

        /**
         * @Description 创建一个文件读入流,读入到全局文本域中
         * @param filePath
         * @param mainTextArea
         * @return void
         */
        public void readFileToAreaText(String filePath,JTextArea mainTextArea){

            BufferedReader bufferedReader = null;
            try {

                bufferedReader = new BufferedReader(new FileReader(filePath));

                char[] buffer = new char[1024];
                int len = 0;
                while ((len = bufferedReader.read(buffer)) != -1) {
                    String str = new String(buffer, 0, len);
                    mainTextArea.append(new String(str));
                }

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (bufferedReader != null){
                    try {
                        bufferedReader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        /**
         * @Description 创建写出文件流
         * @param filePath
         * @param mainTextArea
         * @return void
         */
        public void writeFile(String filePath,JTextArea mainTextArea) {
            BufferedOutputStream bufferedOutputStream = null;
            try {

                //创建一个OutputStream
                bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(filePath));
                String areaText = mainTextArea.getText();
                bufferedOutputStream.write(areaText.getBytes());

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (bufferedOutputStream != null){
                    try {
                        bufferedOutputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
package com.xiaoqi.java;

import javax.swing.*;
import java.lang.reflect.InvocationTargetException;

public class JEditMain {
    public static void createGUI() {
        EditFrame jEdit = new EditFrame("记事本");
        jEdit.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jEdit.setSize(750, 450);
        jEdit.setLocationRelativeTo(null);
        jEdit.setVisible(true);
    }
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            //直接使用方法引用少了行代码
            SwingUtilities.invokeAndWait(JEditMain::createGUI);

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

5. 总结

通过这个简单的文本编辑器项目,我学到了很多关于Swing的知识,同时也意识到还有很多可以改进的地方。比如,我们可以增加更多的功能,如撤销/重做功能、支持多种编码格式等。希望未来能够继续深入学习Swing,开发出更加实用的应用程序。

标签:文本编辑,菜单,void,JMenuItem,mainTextArea,简易,add,Swing,new
From: https://blog.csdn.net/love3512986643/article/details/142058672

相关文章

  • 复制REUSE_ALV_GRID_DISPLAY_LVC,给函数添加简易的F4处理能力
    翻遍REUSE_ALV_GRID_DISPLAY_LVC这个函数我们可以发现,这个函数里预定义了一些事件类型。不过也缺少了一些类型,看看SLIS这个类型池就可以发现,ONF4事件是没有的。为了把这个函数做出通用和简易的,复制这个函数所在的函数组SLVC_FULLSCREEN到ZSLVC_FULLSCREEN.然后我们在这个新函数......
  • 视频怎么加密?加密视频的5大简易方法(2024最全教程)
    《孙子兵法》中有言:“兵者,诡道也”。在当今数字化时代,每一次不经意的疏忽,都可能导致重要的视频资料泄露,给企业带来不可估量的损失。那么,我们应如何使用“诡道”,对视频进行加密呢?以下,是视频加密的五大简易方法。方法一:视频编辑软件内置加密许多专业的视频编辑软件(如AdobePr......
  • 富文本编辑器 实现CTRL+V粘贴图片并上传、WORD粘贴带图片
    编辑器:百度ueditor前端:vue2,vue3,vue-cli,html5需求:复制粘贴word内容图片,word图片转存交互要求:开源,免费,技术支持用户体验:Ctrl+V快捷键操作该说不说,最近这块应该也是挻火的,今天早上又有网友加我微信私聊,说是想了解一下这块的技术和方案。实际我的微信号之前就已经在网上......
  • LLM 工程师入门:生成式AI的简易指南
    编者按:大模型发展了近两年,BaihaiIDP也分享了近百篇LLM各环节的技术洞察,有前沿探讨、有落地实践、有应用经验。但回头来看,我们似乎从来没有认真、从0开始探讨过LLM的基本原理。最近,一些企业客户和伙伴来询问,是否有LLM的从0到1的科普贴。他们说:"虽然在很多场景中,LLM都已......
  • Android中Fragment的最佳实践—简易版的新闻应用
    文章目录Android中Fragment的最佳实践—简易版的新闻应用app/build.gradle当中添加依赖库新建新闻实体类News新建布局文件news_content_frag.xml新建NewsContentFragment类单页模式需新建NewsContentActivity新建news_title_frag.xml新建news_item.xml新建NewsTitleFragm......
  • 一款优秀的文本编辑器:EmEditor Pro
    EmEditor文本编辑器是一款功能强大且非常好用的文本编辑器!它启动速度快,可以完全代替Windows自带的记事本,足以胜任日常的文本编辑工作。良好地支持Unicode和中文字符,还支持20多种编程语言的语法突出显示。并且支持的语法种类可以不断的扩充。具有选择文本列块的功能(按ALT键拖......
  • Linux中的Vim文本编辑器
    Linux中的Vim是一个非常强大的文本编辑器,它提供了丰富的命令来支持各种文本编辑操作。以下是一个Vim常用命令的详细总结,涵盖了基本操作、编辑命令、移动光标、查找替换、保存退出等多个方面。一、基本操作启动Vimvim:直接启动Vim编辑器。vimfilename:打开或创建文件并启......
  • 简易学生信息管理系统课程设计(附源码与详细分析)
    第一章系统概述学生信息管理查询软件是一个教育单位不可缺少的部分它的内容对于学校的决策者和管理者来说都至关重要所以学生信息管理查询软件应该能够为用户提供充足的信息和快捷的查询手段。以前各个学校的学生信息管理基本上都是靠手工进行,但随着各个学校的规模增大,有关学......
  • 【Python游戏开发】用Python实现一个简易的超级玛丽游戏!
    前言小时候最喜欢玩的小游戏就是超级玛丽了,有刺激有又技巧,通关真的很难,救下小公主还被抓走了,唉,心累,最后还是硬着头皮继续闯,终于要通关了,之后再玩还是没有那么容易,哈哈,不知道现在能不能通关,今天就来实现一下,制作一个简易版的超级玛丽游戏如果你正在学习Python并且缺少项目......
  • (二)十分简易快速 自己训练样本 opencv级联lbp分类器 车牌识别
    ......