目录

前言

主界面设计

功能实现

打开

另存为

保存

查找

替换

成员变量

其他方法

警告弹窗

不移动光标更新文本框内容

源代码

总结

转载请注明出处,尊重作者劳动成果

前言

考完试想写敲一下代码就写了一下这个程序,整个也是写了怎么久,救命,因为要搞三下乡活动,还要写调查问卷,所以这个程序断断续续写了挺久的。整个过程中解决了一些问题,但是还是有些问题没有解决,首先这个程序的要求是:

编写一个记事本程序

1.用图形用户界面实现。

2.能实现编辑、保存、另存为、查找替换等功能。

提示:使用文件输入输出流

那接下来就跟着我思路来编写代码吧,因为也是刚接触Java,如果有错误的地方,还希望各位大佬能够不吝赐教,指点一二哈。

主界面设计

这个我倒没有花太多的事件在这个上面,设计也是能简单就简单,就最上方的标题,然后就是两个菜单项,绑定相应的条目,主体的组件就是一个文本域。然后就是条目绑定监听了,我这里是采用的还是ActionListener,要注意的就是原本的文本域中的字体和大小我不是很喜欢,所以我就换掉他了。

//创建选项下面的条目对象(因为后面会用到条目对象)JMenuItem openItem = new JMenuItem("打开");JMenuItem saveItem = new JMenuItem("保存");JMenuItem saveAsItem = new JMenuItem("另存为");JMenuItem findItem = new JMenuItem("查找");JMenuItem replaceItem = new JMenuItem("替换");//创建主体的文本框?要不用一下文本域TextArea mainText = new TextArea();//构造方法private noteFrame() {//初始化框架initJFrame();//初始化菜单initJMenuBar();//初始化面板initPanel();//窗体可见this.setVisible(true);}//初始化框架private void initJFrame() {//设置软件的标题this.setTitle("记事本");//设置窗体位置以及大小this.setSize(1000, 500);//设置窗体居中this.setLocationRelativeTo(null);//关闭按钮的动作为退出this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}//初始化面板private void initPanel() {initModule();//通过this.getContentPane()得到面板数据,然后往里面添加文本域this.getContentPane().add(mainText);}//初始化组件private void initModule() {//调整文本域的字体mainText.setFont(new Font("楷体", Font.BOLD, 15));}//设置菜单,绑定条目private void initJMenuBar() {//初始化菜单//创建整个菜单对象JMenuBar jMenuBar = new JMenuBar();//创建菜单上面的两个选项的对象JMenu paperJMenu = new JMenu("文件");JMenu editJMenu = new JMenu("编辑");//设置条目的大小paperJMenu.setSize(new Dimension(100, 100));//将每一个选项下面的条目去添加到选项当中//文件paperJMenu.add(openItem);paperJMenu.add(saveItem);paperJMenu.add(saveAsItem);//编辑editJMenu.add(findItem);editJMenu.add(replaceItem);//给条目绑定事件openItem.addActionListener(this);saveItem.addActionListener(this);saveAsItem.addActionListener(this);findItem.addActionListener(this);replaceItem.addActionListener(this);//将菜单里面的选项添加到菜单当中jMenuBar.add(paperJMenu);jMenuBar.add(editJMenu);//给整个界面设置菜单this.setJMenuBar(jMenuBar);}

功能实现

打开

这里主要用到的就是FileDialog,刚接触这个是时候我还以为他那个界面是需要自己设计的,当时就吓我一跳了。原来是他会自己出现的,创建他的对象的时候需要用到父类的对象,我当时还以为是我自己写的那个界面类,结果会抛出异常,其实是Frame类的对象,所以我最开始就。

之后可以通过 fd.getDirectory() 得到文件的目录fd.getFile();得到文件的名字(这个应该就是你在页面上面自己填写的名字和自己选择的路径)

我之前看到有一个博主写的strFile判断直接就是strFile!=null,我感觉是错误的,他用getDirectory()方法和getFile()方法得到两个字符串,进行相加之后不是null,而是一个字符串“nullnull”,所以我认为判断应该是写错下面这个才对!strFile.equals(“nullnull”)。

public class Test {public static void main(String[] args) {String str1=null;String str2=null;if(str1==null){System.out.println("str1是空串");}if(str2==null){System.out.println("str2是空串");}String str3=str1+str2;if(str3==null){System.out.println("str3是空串");}System.out.println(str3);System.out.println(str3.length());//字符串的比较if(str3.equals("nullnull")){System.out.println("str3是nullnull");}}}

 Frame frame = new Frame();

Java对话框FileDialog(文件打开与保存)_ruan_luqingnian的博客-CSDN博客https://blog.csdn.net/ruan_luqingnian/article/details/113549586FileInputStream(文件字节输入流)_我为杰伦代言的博客-CSDN博客https://blog.csdn.net/weixin_52385232/article/details/126152428java:IO流(字节数组拷贝之available()方法—不推荐使用)_对抗路、余温的博客-CSDN博客https://blog.csdn.net/qq_24644517/article/details/83415148Java字节输入流的读方法(两种read方法)_java read_NaiQai的博客-CSDN博客https://blog.csdn.net/qq_37693957/article/details/114495193JAVA基础知识之InputStreamReader流_咕噜是个大胖子的博客-CSDN博客https://blog.csdn.net/ai_bao_zi/article/details/81133476Java程序设计-记事本的开发_java记事本项目_Tech行者的博客-CSDN博客https://blog.csdn.net/m0_62338174/article/details/127702434

//执行打开条目对应的响应private void openEvent() {System.out.println("打开");//这里是本人第一次用到FileDialog类,所以理解还不是和透彻,容易问一下蠢问题,还希望各位大佬多多包涵//这里的frame和noteFrame没有绑定的关系,但是可以响应的,按照要求的话FileDialog的第一个参数是指父窗口//这里不能用noteFrame(类/对象本身),不然会异常抛出//Exception in thread "main" Exception in thread "main" Exception in thread "main" java.lang.StackOverflowErrorFileDialog fd = new FileDialog(frame, "打开", FileDialog.LOAD);//loadfd.setVisible(true);//对话框可视(不然是不会显示的)//getDirectory()获取用户选择的目录的路径//getFile()获取用户选择的文件的名称//两个方法都需要在对话框关闭后才能调用//文件的绝对路径String strFile = fd.getDirectory() + fd.getFile();//nullnull,两个空字符拼接if (!strFile.equals("nullnull")) {//个人认为strFile!=null不正确try {//更新保存在类中的文件路径filePath = strFile;//判断文件名是否带.txt后缀String pattern = ".*\\.txt$";if (!strFile.matches(pattern)) {//如果文件不带路径就给他加上strFile += ".txt";}System.out.println(strFile);int rs;//文件字节输入流FileInputStream fis = new FileInputStream(strFile);//字节输入流转换为字符输入流(输入选择GBK编码模式)InputStreamReader isr = new InputStreamReader(fis, "GBK");//available获取读的文件所有的字节个数//byte b[]=new byte[fis.available()];//依次读取一个一个的字节数据到b数组里面//fis.read(b);//将取出来的值赋值到文本域中(new String(b)将字符转换成字符串//mainText.setText(new String(b));//fis.close();//文本域里面的内容String strText = "";//提取字符while ((rs = isr.read()) != -1) {strText += ((char) rs);}//将取出来的值赋值到文本域中//mainText.setText(strText);//保存光标的插入文本内容retainCursorLocation(strText);//System.out.println(strText);//mainText.setFont(new Font("楷体", Font.BOLD, 15));isr.close();} catch (Exception exception) {//用e和响应方法的e冲突了exception.printStackTrace();}}}

另存为

这个就和打开是一样的了,不过这创建对象的参数是FileDialog.SAVE,这里就遇到了第一个让我头疼的问题了,字符编码,网上的很多记事本吧,他就是用字节流来输入输出这就没有体现Java的优势吧,而且中国人实现记事本只能记录英文是什么鬼,所以还是要用字符流来处理,这个时候就有乱码的问题了,我这里遇到的几个问题就是。

1.电脑记事本创建,Java程序记事本打开出现乱码

2.Java程序记事本保存,用电脑记事本打开出现乱码

3.Java程序记事本保存,用电脑记事本打开没有问题,但是再次用Java程序记事本打开出现乱码

4.Java程序记事本打开电脑创建文本文件的没有出现乱码,但是用Java程序保存之后再用Java程序打开出现乱码,值得注意的是用电脑记事本打开那个文件没有出现乱码。

这就很头痛了,像这种乱码问题很明显就是编码的问题因为英文字符此时是没有发生改变的,通过查资料发现window下的记事本采用的默认是GBK编码,Java程序里面采用的UTF-8的编码方式,这其实对于程序里面的记事本显示的内容其实就是一个字符串,所以只要能正确提取GBK编码的文件以及按GBK编码文件形式的写入,就没有问题了。

问题1:编码不同

解决:统一采用GBK编码的方式

OutputStream流写入中文乱码问题_outputstream乱码问题_禾苗码上的博客-CSDN博客https://blog.csdn.net/qq_42195589/article/details/125172030UTF-8 ASCII GBK GB2312 GB18030等字符编码的关系_standardcharsets没有gbk_cszhang570221322的博客-CSDN博客https://blog.csdn.net/cszhang570221322/article/details/84786918

//执行另存为条目对应的响应private void saveAsEvent() {System.out.println("另存为");FileDialog fd = new FileDialog(frame, "保存", FileDialog.SAVE);//savefd.setVisible(true);//对话框可视(不然是不会显示的)//获取fd对话框的目录String fdir = fd.getDirectory();//记得加上.txt的后缀,填的时候就只要填文件名就行了//File file = new File(fd.getFile() + ".txt");String fname = fd.getFile();//判断文件名是否带.txt后缀String pattern = ".*\\.txt$";if (!fname.matches(pattern)) {//如果文件不带后缀就给他加上fname += ".txt";}//得到文本域中的内容String strText = mainText.getText();//System.out.println(strText);try {//创建文件,要带有路径FileOutputStream fos = new FileOutputStream(fdir + fname);//选用GBK编码的方式输入OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");//字符数据的缓冲输出BufferedWriter bw = new BufferedWriter(osw);//更新保存在类中的文件路径filePath = fdir + fname;//把字符串写入到文件中bw.write(strText);bw.close();} catch (Exception exception) {exception.printStackTrace();}}

保存

这个我的想法就是要体现他和另存为条目的区别,我这里处理就是用一个成员变量去标记,只有第一次选择保存的时候,他的表现和另存为一样。如果他先选择了打开文件或者另存为文件了,这个时候用保存就可以不用打开那个选择位置的界面,那个界面其实每次都有的话还是挺麻烦的,但是要注意的是文件的内容还是需要更新的。

 //用一个成员变量来标识,当他为空的时候说明他保存和另存为的结果一致String filePath = null;

打开和保存的时候我感觉有一个麻烦的点,就是那个文件有时候带后缀有时候有不带后缀,一下就产生报错,所以我就统一给他加上了,没有后缀就加上后缀,用后缀就不用加,用了一个正则表达式。

/判断文件名是否带.txt后缀String pattern = ".*\\.txt$";if (!fname.matches(pattern)) { //如果文件不带后缀就给他加上fname += ".txt";}

匹配文件后缀名的正则表达式_正则表达式匹配文件后缀_耶耶as的博客-CSDN博客https://blog.csdn.net/ASIYAas/article/details/124626050问题二:如何体现“保存”和“另存为”的区别

解决:用一个成员变量来标记他是不是第一次选择保存。

//执行保存条目对应的响应private void saveEvent() {System.out.println("保存");//filePath为空执行的操作就和另存为的操作一致了if (filePath == null) {System.out.println("保存");FileDialog fd = new FileDialog(frame, "保存", FileDialog.SAVE);//savefd.setVisible(true);//对话框可视(不然是不会显示的)//获取fd对话框的目录String fdir = fd.getDirectory();//记得加上.txt的后缀,填的时候就只要填文件名就行了//File file = new File(fd.getFile() + ".txt");String fname = fd.getFile();//判断文件名是否带.txt后缀String pattern = ".*\\.txt$";if (!fname.matches(pattern)) {//如果文件不带后缀就给他加上fname += ".txt";}//得到文本域中的内容String strText = mainText.getText();//System.out.println(strText);try {//创建文件,要带有路径FileOutputStream fos = new FileOutputStream(fdir + fname);//选用GBK编码的方式输入OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");//字符数据的缓冲输出BufferedWriter bw = new BufferedWriter(osw);//更新保存在类中的文件路径filePath = fdir + fname;//把字符串写入到文件中bw.write(strText);bw.close();} catch (Exception exception) {exception.printStackTrace();}} else {//判断文件名是否带.txt后缀String pattern = ".*\\.txt$";if (!filePath.matches(pattern)) {//如果文件不带后缀就给他加上filePath += ".txt";}//得到文本域中的内容String strText = mainText.getText();System.out.println(filePath);//System.out.println(strText);try {//创建文件,要带有路径FileOutputStream fos = new FileOutputStream(filePath);//选用GBK编码的方式输入OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");//字符数据的缓冲输出BufferedWriter bw = new BufferedWriter(osw);//把字符串写入到文件中bw.write(strText);bw.close();} catch (Exception exception) {exception.printStackTrace();}}}

查找

查找要实现的就是首先要能找到字符串的位置,不仅是向下,还有向上查询。这个界面其实也设计了这么久,想让按钮里面的字能够显示出来,按钮的大小同时也不能太大。这个界面的话我是设置成一个弹窗的形式,对后面还是有一点问题的。取消的功能就是直接关闭了。

java记事本实现查找功能_java实现搜索框搜索文本_云边守望者的博客-CSDN博客https://blog.csdn.net/m0_62068664/article/details/129109946String类的indexOf方法的用法_string.indexof_zzqcsdn123的博客-CSDN博客https://blog.csdn.net/zzqcsdn123/article/details/85128456isEmpty和null有什么区别_清如许.的博客-CSDN博客https://blog.csdn.net/MacWx/article/details/93460684JOptionPane详解_tjk123456的博客-CSDN博客https://blog.csdn.net/tjk123456/article/details/77868034Java对话框(JDialog类和JOptionPane类)_joptionpane依赖_qq_37723158的博客-CSDN博客https://blog.csdn.net/qq_37723158/article/details/79025152

问题三:如何实现“向上查找”和“向下查找”

调用indexOf()方法和lastIndexOf()方法。

问题四:界面的位置如何设计

我这里是通过方法得到了屏幕的宽和高,然后按照比例确定了查找界面的位置

问题五:查找到的内容怎么知道找到了

这个是用到了光标,设置光标的起点和终点。同时增加了一个模式对话框。但这还有一个问题没有解决,就是你需要把查找的弹窗关闭之后光标才会显示。

问题六:这个光标的移动怎么怪怪的,怎么每次都到最后去了

这个其实我也找了很久,原本就是通过设置光标的起点和终点,到时候再得到就是了,但是光标总是跑后面去,这个查资料是说,当你对文本框调用setText()方法的时候,光标就会移动到末尾,而且当你从新获得焦点的时候,对文本框写数据的时候也会移动光标的位置。

这个是通过两个成员变量来标记光标指向查找到字符串的起点和终点。

//保存查找的位置int findStart = 0;int findEnd = 0;

问题七:文本框中没有内容怎么办

没有得到内容肯定就应该报错,输出警告就行了,要注意的就是这个判断,首先要放在按钮响应事件里面才会响应用,而且superString==null/superString==””都不行,我用的是superString.isEmpty()来判断。

问题八:文本域中含义目标字符串,但是仍显示没有查找到。

未解决:这个就是一个很巧的事情,就是你先查找一个字符串,然后通过移动让记录光标的位置卡在之后要查找的字符串的位置附近,就是他的位置不对,而查找不是每次从0开始的,我是在程序运行的时候初始化了一次,也就是他之后就是在上次查找的基础上查找。

解决思路:其实有一个算是简单的方法,可以增加一个按钮,按下之后,光标记录的开始位置和终止位置都直接归零,从头开始查找。

问题九:查找不到,光标随意移动

未解决:这个自己本身写文件可以查找,但是导入文件之后查找功能就失灵了,但是全部替换功能应该是没有问题,这个我也不知道原来,用知道的大佬可以指点一二。

//执行查找条目对应的响应public void findEvent() {System.out.println("查找");//弹窗JDialog jDialog = new JDialog();//创建弹窗对象jDialog.setTitle("查找");//设置弹窗标题,和Frame差不多,可能还要通过标签来提示jDialog.setSize(500, 100);//设置弹窗的大小jDialog.setAlwaysOnTop(true);//让弹窗置顶jDialog.setModal(true);//弹窗不关闭则无法操作下面的界面jDialog.setModal(true);//设置对话框为模式对话框//获取屏幕的宽度和高度int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;//获取JDialog的宽度和高度int dialogWidth = jDialog.getWidth();int dialogHeight = jDialog.getHeight();//计算对话框应该居中显示时的x和y坐标(相对电脑屏幕)int x = (screenWidth - dialogWidth) * 3 / 4;int y = (screenHeight - dialogHeight) / 4;//设置对话框的位置jDialog.setLocation(x, y);//组件信息JTextField findText = new JTextField();JButton findNextButton = new JButton("向下搜索");JButton findPreviousButton = new JButton("向上搜索");JButton cancelButton = new JButton("取消");//设置文本框位置和大小findText.setBounds(17, 0, 450, 30);//设置按钮的位置findNextButton.setBounds(145, 33, 100, 27);findNextButton.setFont(new Font("楷体", Font.BOLD, 10));findPreviousButton.setBounds(255, 33, 100, 27);findPreviousButton.setFont(new Font("楷体", Font.BOLD, 10));cancelButton.setBounds(365, 33, 100, 27);cancelButton.setFont(new Font("楷体", Font.BOLD, 10));//这个也要取消布局管理器才行jDialog.getContentPane().setLayout(null);//往弹窗中添加组件jDialog.getContentPane().add(findText);jDialog.getContentPane().add(findNextButton);jDialog.getContentPane().add(findPreviousButton);jDialog.getContentPane().add(cancelButton);//绑定事件findNextButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("向下搜索")) {System.out.println("向下搜索");//用来标记警告,如果记事本和搜索框都是空,显示一个就可以了boolean flagWarning = true;//得到文本域中的内容// 1.这个判断首先要放在按钮响应事件里面才会响应// 2.用superString==null/superString==""都不行,我用的是superString.isEmpty()String superString = mainText.getText();if (superString.isEmpty()) {//System.out.println("记事本中的字符串不能为空");warning("记事本中的字符串不能为空");flagWarning = false;}//System.out.println(superString);//获取查询框中的字符串String subString = findText.getText();if (subString.isEmpty()) {//System.out.println("查询框中的字符串不能为空");if (flagWarning) {warning("查询框中的字符串不能为空");flagWarning = false;}}//System.out.println(subString);//要没有出现弹窗才能继续查询,不然就会出现多个弹窗if (flagWarning) {//查找subString出现的位置(往后查找)getSelectionEnd得到光标结束int index = superString.indexOf(subString, findEnd);if (index != -1) {//设置光标开始位置mainText.setSelectionStart(index);//设置光标结束位置mainText.setSelectionEnd(index + subString.length());//保存位置,书写的时候光标也会移动的findStart = index;findEnd = index + subString.length();//获取焦点(不能重新获得焦点,会移动到最后)//mainText.requestFocus();JOptionPane.showMessageDialog(noteFrame.this, "找到匹配的文本");//标记可以替换ableReplace = true;} else {//标记不可以替换JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");ableReplace = false;}}}}});findPreviousButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JButton button = (JButton) e.getSource();//获得触发此次动作事件的按钮对象String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("向上搜索")) {System.out.println("向上搜索");//用来标记警告,如果记事本和搜索框都是空,显示一个就可以了boolean flagWarning = true;//得到文本域中的内容// 1.这个判断首先要放在按钮响应事件里面才会响应// 2.用superString==null/superString==""都不行,我用的是superString.isEmpty()String superString = mainText.getText();if (superString.isEmpty()) {//System.out.println("记事本中的字符串不能为空");warning("记事本中的字符串不能为空");flagWarning = false;}//System.out.println(superString);//获取查询框中的字符串String subString = findText.getText();if (subString.isEmpty()) {//System.out.println("查询框中的字符串不能为空");if (flagWarning) {warning("查询框中的字符串不能为空");flagWarning = false;}}//System.out.println(subString);if (flagWarning) {//查找subString出现的位置(往前查找)int index = superString.lastIndexOf(subString, findStart - 1);if (index != -1) {//设置光标开始位置mainText.setSelectionStart(index);//设置光标结束位置mainText.setSelectionEnd(index + subString.length());//保存位置,书写的时候光标也会移动的findStart = index;findEnd = index + subString.length();//获取焦点(不能重新获得焦点,会移动到最后)//mainText.requestFocus();JOptionPane.showMessageDialog(noteFrame.this, "找到匹配的文本");//标记可以发生替换ableReplace = true;} else {JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");//标记不可以发生替换ableReplace = false;}}}}});cancelButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JButton button = (JButton) e.getSource();//获得触发此次动作事件的按钮对象String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("取消")) {System.out.println("取消");jDialog.dispose();//关闭对话框}}});jDialog.setVisible(true);//让弹窗显示出来}

替换

替换的功能就是查找功能的升级版,在查找的基础上进行替换,我这个替换功能就有点鸡肋,要先查找之后才能替换,当然全部替换除外。

String的几种replace()方法_string的replace方法_小码哥222的博客-CSDN博客https://blog.csdn.net/qq_38737586/article/details/99224148

问题十:如何实现全部替换

直接调用replaceAll()方法,看他的返回值和原来的字符串相比是否发生了改变,发生了改变就说明可以替换,更新一下再界面中显示的内容。

问题十一:如何实现单个替换

我这个是通过之后记录的光标的位置,如果位置中间的字符串和带替换的字符串是一样的就可以替换,然后需要用到StringBuilder类,String好像没有这个功能。这个光标的位置还是需要更新一下的,光标起点的位置保持不变,但是终点的位置发生改变,以为替换前后字符串的长度可能不一致。

//实现替换条目的功能private void replaceEvent() {System.out.println("替换");//弹窗JDialog jDialog = new JDialog();//创建弹窗对象jDialog.setTitle("替换");//设置弹窗标题,和Frame差不多,可能还要通过标签来提示jDialog.setSize(500, 150);//设置弹窗的大小jDialog.setAlwaysOnTop(true);//让弹窗置顶jDialog.setModal(true);//弹窗不关闭则无法操作下面的界面jDialog.setModal(true);//设置对话框为模式对话框//获取屏幕的宽度和高度int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;//获取JDialog的宽度和高度int dialogWidth = jDialog.getWidth();int dialogHeight = jDialog.getHeight();//计算对话框应该居中显示时的x和y坐标(相对电脑屏幕)int x = (screenWidth - dialogWidth) * 3 / 4;int y = (screenHeight - dialogHeight) / 4;//设置对话框的位置jDialog.setLocation(x, y);//组件信息JTextField findText = new JTextField();JTextField replaceText = new JTextField();JButton findNextButton = new JButton("向下搜索");JButton findPreviousButton = new JButton("向上搜索");JButton cancelButton = new JButton("取消");JButton replaceButton = new JButton("替换");JButton replaceAllButton = new JButton("替换所有");//设置文本框位置和大小findText.setBounds(17, 0, 450, 30);replaceText.setBounds(17, 35, 450, 30);//设置按钮的位置findNextButton.setBounds(10, 70, 90, 27);findNextButton.setFont(new Font("楷体", Font.BOLD, 10));findPreviousButton.setBounds(105, 70, 90, 27);findPreviousButton.setFont(new Font("楷体", Font.BOLD, 10));replaceButton.setBounds(200, 70, 90, 27);replaceButton.setFont(new Font("楷体", Font.BOLD, 10));replaceAllButton.setBounds(295, 70, 90, 27);replaceAllButton.setFont(new Font("楷体", Font.BOLD, 10));cancelButton.setBounds(390, 70, 90, 27);cancelButton.setFont(new Font("楷体", Font.BOLD, 10));//这个也要取消布局管理器才行jDialog.getContentPane().setLayout(null);//往弹窗中添加组件jDialog.getContentPane().add(findText);jDialog.getContentPane().add(replaceText);jDialog.getContentPane().add(findNextButton);jDialog.getContentPane().add(findPreviousButton);jDialog.getContentPane().add(cancelButton);jDialog.getContentPane().add(replaceButton);jDialog.getContentPane().add(replaceAllButton);//绑定事件findNextButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JButton button = (JButton) e.getSource();//获得触发此次动作事件的按钮对象String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("向下搜索")) {System.out.println("向下搜索");//用来标记警告,如果记事本和搜索框都是空,显示一个就可以了boolean flagWarning = true;//得到文本域中的内容// 1.这个判断首先要放在按钮响应事件里面才会响应// 2.用superString==null/superString==""都不行,我用的是superString.isEmpty()String superString = mainText.getText();if (superString.isEmpty()) {//System.out.println("记事本中的字符串不能为空");warning("记事本中的字符串不能为空");flagWarning = false;}//System.out.println(superString);//获取查询框中的字符串String subString = findText.getText();if (subString.isEmpty()) {//System.out.println("查询框中的字符串不能为空");if (flagWarning) {warning("查询框中的字符串不能为空");flagWarning = false;}}//System.out.println(subString);//要没有出现弹窗才能继续查询,不然就会出现多个弹窗if (flagWarning) {//查找subString出现的位置(往后查找)getSelectionEnd得到光标结束//int index = superString.indexOf(subString, replaceEnd);int index = superString.indexOf(subString, findEnd);if (index != -1) {//设置光标开始位置mainText.setSelectionStart(index);//设置光标结束位置mainText.setSelectionEnd(index + subString.length());//保存位置,书写的时候光标也会移动的findStart = index;findEnd = index + subString.length();//replaceStart = index;//replaceEnd = index + subString.length();//获取焦点(不能重新获得焦点,会移动到最后)//mainText.requestFocus();//标记可以替换ableReplace = true;JOptionPane.showMessageDialog(noteFrame.this, "找到匹配的文本");} else {//标记不可以替换ableReplace = false;JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");}}}}});findPreviousButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JButton button = (JButton) e.getSource();//获得触发此次动作事件的按钮对象String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("向上搜索")) {System.out.println("向上搜索");//用来标记警告,如果记事本和搜索框都是空,显示一个就可以了boolean flagWarning = true;//得到文本域中的内容// 1.这个判断首先要放在按钮响应事件里面才会响应// 2.用superString==null/superString==""都不行,我用的是superString.isEmpty()String superString = mainText.getText();if (superString.isEmpty()) {//System.out.println("记事本中的字符串不能为空");warning("记事本中的字符串不能为空");flagWarning = false;}//System.out.println(superString);//获取查询框中的字符串String subString = findText.getText();if (subString.isEmpty()) {//System.out.println("查询框中的字符串不能为空");if (flagWarning) {warning("查询框中的字符串不能为空");flagWarning = false;}}//System.out.println(subString);if (flagWarning) {//查找subString出现的位置(往前查找)//int index = superString.lastIndexOf(subString, replaceStart - 1);int index = superString.lastIndexOf(subString, findStart - 1);if (index != -1) {//设置光标开始位置mainText.setSelectionStart(index);//设置光标结束位置mainText.setSelectionEnd(index + subString.length());//保存位置,书写的时候光标也会移动的findStart = index;findEnd = index + subString.length();//replaceStart = index;//replaceEnd = index + subString.length();//获取焦点(不能重新获得焦点,会移动到最后)//mainText.requestFocus();//标记可以替换ableReplace = true;JOptionPane.showMessageDialog(noteFrame.this, "找到匹配的文本");} else {//标记不可以替换ableReplace = false;JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");}}}}});replaceButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("替换")) {System.out.println("替换");//用来标记警告,如果记事本,搜索框,替换框都是空,显示一个就可以了boolean flagWarning = true;//得到文本域中的内容// 1.这个判断首先要放在按钮响应事件里面才会响应// 2.用superString==null/superString==""都不行,我用的是superString.isEmpty()String superString = mainText.getText();if (superString.isEmpty()) {//System.out.println("记事本中的字符串不能为空");warning("记事本中的字符串不能为空");flagWarning = false;}//System.out.println(superString);//获取查询框中的字符串String formerString = findText.getText();if (formerString.isEmpty()) {//System.out.println("查询框中的字符串不能为空");if (flagWarning) {flagWarning = false;warning("查询框中的字符串不能为空");}}//System.out.println(formerString);//获取替换框中的字符串String newString = replaceText.getText();if (newString.isEmpty()) {//System.out.println("替换框中的字符串不能为空");if (flagWarning) {warning("替换框中的字符串不能为空");flagWarning = false;}}//System.out.println(newString);//要没有出现弹窗才能继续查询,不然就会出现多个弹窗if (flagWarning && ableReplace) {//替换单个好像是要用StringBuilder,String没有这么高级// 只能替换第一个,也可以简化一下程序,每次替换第一个,就不用移动了//这个可以两次的字符串不一样,就是光标指向的字符串和文本框里面不一样String result = superString.substring(findStart, findEnd);//两个一样才能替换if (formerString.equals(result)) {StringBuilder sb = new StringBuilder(superString);//用之前找到的字符串来替换sb.replace(findStart, findEnd, newString);//更新光标的结束位置(开始位置保持不变)findEnd = findStart + newString.length();//更新文本域中的内容retainCursorLocation(sb.toString());JOptionPane.showMessageDialog(noteFrame.this, "成功替换");} else {JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");}} else {JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");}}}});replaceAllButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("替换所有")) {System.out.println("替换所有");//用来标记警告,如果记事本,搜索框,替换框都是空,显示一个就可以了boolean flagWarning = true;//得到文本域中的内容// 1.这个判断首先要放在按钮响应事件里面才会响应// 2.用superString==null/superString==""都不行,我用的是superString.isEmpty()String superString = mainText.getText();if (superString.isEmpty()) {//System.out.println("记事本中的字符串不能为空");warning("记事本中的字符串不能为空");flagWarning = false;}//System.out.println(superString);//获取查询框中的字符串String formerString = findText.getText();if (formerString.isEmpty()) {//System.out.println("查询框中的字符串不能为空");if (flagWarning) {flagWarning = false;warning("查询框中的字符串不能为空");}}//System.out.println(formerString);//获取替换框中的字符串String newString = replaceText.getText();if (newString.isEmpty()) {//System.out.println("替换框中的字符串不能为空");if (flagWarning) {warning("替换框中的字符串不能为空");flagWarning = false;}}//System.out.println(newString);//要没有出现弹窗才能继续查询,不然就会出现多个弹窗if (flagWarning) {//替换所有的字符串String result = superString.replaceAll(formerString, newString);//两个不相同就说明替换成功了,不然就会原样返回if (!superString.equals(result)) {//更新文本域中的内容retainCursorLocation(result);JOptionPane.showMessageDialog(noteFrame.this, "成功替换满足要求的文本");} else {JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");}}}}});cancelButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JButton button = (JButton) e.getSource();//获得触发此次动作事件的按钮对象String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("取消")) {System.out.println("取消");jDialog.dispose();//关闭对话框}}});jDialog.setVisible(true);//让弹窗显示出来}

成员变量

相关成员变量在之前都有讲解,基本上都是起标记作用的。

Frame frame = new Frame();//创建选项下面的条目对象(因为后面会用到条目对象)JMenuItem openItem = new JMenuItem("打开");JMenuItem saveItem = new JMenuItem("保存");JMenuItem saveAsItem = new JMenuItem("另存为");JMenuItem findItem = new JMenuItem("查找");JMenuItem replaceItem = new JMenuItem("替换");//创建主体的文本框?要不用一下文本域TextArea mainText = new TextArea();//用一个成员变量来标识,当他为空的时候说明他保存和另存为的结果一致String filePath = null;//保存查找的位置int findStart = 0;int findEnd = 0;//保存替换的位置(和保存的统一算了)//int replaceStart = 0;//int replaceEnd = 0;//标记他是否查找到了替换的字符串boolean ableReplace = false;

其他方法

警告弹窗

封装后的作用就是传入文本,显示一个固定大小的弹窗,传入的字符串就是弹窗中显示的标签。

//输出警告弹窗private void warning(String str) {//添加一个弹窗的警告JDialog jDialog = new JDialog();//创建弹窗对象jDialog.setTitle("警告");//设置弹窗标题,和Frame差不多,可能还要通过标签来提示jDialog.setSize(500, 400);//设置弹窗的大小jDialog.setAlwaysOnTop(true);//让弹窗置顶jDialog.setLocationRelativeTo(null);//让弹窗居中jDialog.setModal(true);//弹窗不关闭则无法操作下面的界面//警告标签,放在弹窗里面final JLabel warningLabel = new JLabel(str, JLabel.CENTER);//设置字体的类型,加粗,和大小warningLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 30));//标签的位置和大小warningLabel.setBounds(0, 100, 500, 100);//这个也要取消布局管理器才行//jDialog.getContentPane().setLayout(null);//往弹窗中添加标签(垂直加居中放置标签)jDialog.getContentPane().add(warningLabel, BorderLayout.CENTER);jDialog.setVisible(true);//让弹窗显示出来}

不移动光标更新文本框内容

让移动到最后面的光标回到之前的位置上面来。

//每次插入文本之后光标会有移动到最后面,所以要保存一下private void retainCursorLocation(String strText) {mainText.setText(strText);mainText.setFont(new Font("楷体", Font.BOLD, 15));//恢复之前的位置mainText.setSelectionStart(findStart);mainText.setSelectionEnd(findEnd);}

源代码

import javax.swing.*;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.*;public class noteFrame extends JFrame implements ActionListener {//主方法public static void main(String[] args) {new noteFrame();}Frame frame = new Frame();//创建选项下面的条目对象(因为后面会用到条目对象)JMenuItem openItem = new JMenuItem("打开");JMenuItem saveItem = new JMenuItem("保存");JMenuItem saveAsItem = new JMenuItem("另存为");JMenuItem findItem = new JMenuItem("查找");JMenuItem replaceItem = new JMenuItem("替换");//创建主体的文本框?要不用一下文本域TextArea mainText = new TextArea();//用一个成员变量来标识,当他为空的时候说明他保存和另存为的结果一致String filePath = null;//保存查找的位置int findStart = 0;int findEnd = 0;//保存替换的位置(和保存的统一算了)//int replaceStart = 0;//int replaceEnd = 0;//标记他是否查找到了替换的字符串boolean ableReplace = false;//构造方法private noteFrame() {//初始化框架initJFrame();//初始化菜单initJMenuBar();//初始化面板initPanel();//窗体可见this.setVisible(true);}//初始化框架private void initJFrame() {//设置软件的标题this.setTitle("记事本");//设置窗体位置以及大小this.setSize(1000, 500);//设置窗体居中this.setLocationRelativeTo(null);//关闭按钮的动作为退出this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}//初始化面板private void initPanel() {initModule();//通过this.getContentPane()得到面板数据,然后往里面添加文本域this.getContentPane().add(mainText);}//初始化组件private void initModule() {//调整文本域的字体mainText.setFont(new Font("楷体", Font.BOLD, 15));}//设置菜单,绑定条目private void initJMenuBar() {//初始化菜单//创建整个菜单对象JMenuBar jMenuBar = new JMenuBar();//创建菜单上面的两个选项的对象JMenu paperJMenu = new JMenu("文件");JMenu editJMenu = new JMenu("编辑");//设置条目的大小paperJMenu.setSize(new Dimension(100, 100));//将每一个选项下面的条目去添加到选项当中//文件paperJMenu.add(openItem);paperJMenu.add(saveItem);paperJMenu.add(saveAsItem);//编辑editJMenu.add(findItem);editJMenu.add(replaceItem);//给条目绑定事件openItem.addActionListener(this);saveItem.addActionListener(this);saveAsItem.addActionListener(this);findItem.addActionListener(this);replaceItem.addActionListener(this);//将菜单里面的选项添加到菜单当中jMenuBar.add(paperJMenu);jMenuBar.add(editJMenu);//给整个界面设置菜单this.setJMenuBar(jMenuBar);}@Overridepublic void actionPerformed(ActionEvent e) {//获取当前被点击的条目对象Object obj = e.getSource();if (obj == openItem) {openEvent();} else if (obj == saveItem) {saveEvent();} else if (obj == saveAsItem) {saveAsEvent();} else if (obj == findItem) {findEvent();} else if (obj == replaceItem) {replaceEvent();}}//执行打开条目对应的响应private void openEvent() {System.out.println("打开");//这里是本人第一次用到FileDialog类,所以理解还不是和透彻,容易问一下蠢问题,还希望各位大佬多多包涵//这里的frame和noteFrame没有绑定的关系,但是可以响应的,按照要求的话FileDialog的第一个参数是指父窗口//这里不能用noteFrame(类/对象本身),不然会异常抛出//Exception in thread "main" Exception in thread "main" Exception in thread "main" java.lang.StackOverflowErrorFileDialog fd = new FileDialog(frame, "打开", FileDialog.LOAD);//loadfd.setVisible(true);//对话框可视(不然是不会显示的)//getDirectory()获取用户选择的目录的路径//getFile()获取用户选择的文件的名称//两个方法都需要在对话框关闭后才能调用//文件的绝对路径String strFile = fd.getDirectory() + fd.getFile();//nullnull,两个空字符拼接if (!strFile.equals("nullnull")) {//个人认为strFile!=null不正确try {//更新保存在类中的文件路径filePath = strFile;//判断文件名是否带.txt后缀String pattern = ".*\\.txt$";if (!strFile.matches(pattern)) {//如果文件不带路径就给他加上strFile += ".txt";}System.out.println(strFile);int rs;//文件字节输入流FileInputStream fis = new FileInputStream(strFile);//字节输入流转换为字符输入流(输入选择GBK编码模式)InputStreamReader isr = new InputStreamReader(fis, "GBK");//available获取读的文件所有的字节个数//byte b[]=new byte[fis.available()];//依次读取一个一个的字节数据到b数组里面//fis.read(b);//将取出来的值赋值到文本域中(new String(b)将字符转换成字符串//mainText.setText(new String(b));//fis.close();//文本域里面的内容String strText = "";//提取字符while ((rs = isr.read()) != -1) {strText += ((char) rs);}//将取出来的值赋值到文本域中//mainText.setText(strText);//保存光标的插入文本内容retainCursorLocation(strText);//System.out.println(strText);//mainText.setFont(new Font("楷体", Font.BOLD, 15));isr.close();} catch (Exception exception) {//用e和响应方法的e冲突了exception.printStackTrace();}}}//执行保存条目对应的响应private void saveEvent() {System.out.println("保存");//filePath为空执行的操作就和另存为的操作一致了if (filePath == null) {System.out.println("保存");FileDialog fd = new FileDialog(frame, "保存", FileDialog.SAVE);//savefd.setVisible(true);//对话框可视(不然是不会显示的)//获取fd对话框的目录String fdir = fd.getDirectory();//记得加上.txt的后缀,填的时候就只要填文件名就行了//File file = new File(fd.getFile() + ".txt");String fname = fd.getFile();//判断文件名是否带.txt后缀String pattern = ".*\\.txt$";if (!fname.matches(pattern)) {//如果文件不带后缀就给他加上fname += ".txt";}//得到文本域中的内容String strText = mainText.getText();//System.out.println(strText);try {//创建文件,要带有路径FileOutputStream fos = new FileOutputStream(fdir + fname);//选用GBK编码的方式输入OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");//字符数据的缓冲输出BufferedWriter bw = new BufferedWriter(osw);//更新保存在类中的文件路径filePath = fdir + fname;//把字符串写入到文件中bw.write(strText);bw.close();} catch (Exception exception) {exception.printStackTrace();}} else {//判断文件名是否带.txt后缀String pattern = ".*\\.txt$";if (!filePath.matches(pattern)) {//如果文件不带后缀就给他加上filePath += ".txt";}//得到文本域中的内容String strText = mainText.getText();System.out.println(filePath);//System.out.println(strText);try {//创建文件,要带有路径FileOutputStream fos = new FileOutputStream(filePath);//选用GBK编码的方式输入OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");//字符数据的缓冲输出BufferedWriter bw = new BufferedWriter(osw);//把字符串写入到文件中bw.write(strText);bw.close();} catch (Exception exception) {exception.printStackTrace();}}}//执行另存为条目对应的响应private void saveAsEvent() {System.out.println("另存为");FileDialog fd = new FileDialog(frame, "保存", FileDialog.SAVE);//savefd.setVisible(true);//对话框可视(不然是不会显示的)//获取fd对话框的目录String fdir = fd.getDirectory();//记得加上.txt的后缀,填的时候就只要填文件名就行了//File file = new File(fd.getFile() + ".txt");String fname = fd.getFile();//判断文件名是否带.txt后缀String pattern = ".*\\.txt$";if (!fname.matches(pattern)) {//如果文件不带后缀就给他加上fname += ".txt";}//得到文本域中的内容String strText = mainText.getText();//System.out.println(strText);try {//创建文件,要带有路径FileOutputStream fos = new FileOutputStream(fdir + fname);//选用GBK编码的方式输入OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");//字符数据的缓冲输出BufferedWriter bw = new BufferedWriter(osw);//更新保存在类中的文件路径filePath = fdir + fname;//把字符串写入到文件中bw.write(strText);bw.close();} catch (Exception exception) {exception.printStackTrace();}}//执行查找条目对应的响应public void findEvent() {System.out.println("查找");//弹窗JDialog jDialog = new JDialog();//创建弹窗对象jDialog.setTitle("查找");//设置弹窗标题,和Frame差不多,可能还要通过标签来提示jDialog.setSize(500, 100);//设置弹窗的大小jDialog.setAlwaysOnTop(true);//让弹窗置顶jDialog.setModal(true);//弹窗不关闭则无法操作下面的界面jDialog.setModal(true);//设置对话框为模式对话框//获取屏幕的宽度和高度int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;//获取JDialog的宽度和高度int dialogWidth = jDialog.getWidth();int dialogHeight = jDialog.getHeight();//计算对话框应该居中显示时的x和y坐标(相对电脑屏幕)int x = (screenWidth - dialogWidth) * 3 / 4;int y = (screenHeight - dialogHeight) / 4;//设置对话框的位置jDialog.setLocation(x, y);//组件信息JTextField findText = new JTextField();JButton findNextButton = new JButton("向下搜索");JButton findPreviousButton = new JButton("向上搜索");JButton cancelButton = new JButton("取消");//设置文本框位置和大小findText.setBounds(17, 0, 450, 30);//设置按钮的位置findNextButton.setBounds(145, 33, 100, 27);findNextButton.setFont(new Font("楷体", Font.BOLD, 10));findPreviousButton.setBounds(255, 33, 100, 27);findPreviousButton.setFont(new Font("楷体", Font.BOLD, 10));cancelButton.setBounds(365, 33, 100, 27);cancelButton.setFont(new Font("楷体", Font.BOLD, 10));//这个也要取消布局管理器才行jDialog.getContentPane().setLayout(null);//往弹窗中添加组件jDialog.getContentPane().add(findText);jDialog.getContentPane().add(findNextButton);jDialog.getContentPane().add(findPreviousButton);jDialog.getContentPane().add(cancelButton);//绑定事件findNextButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("向下搜索")) {System.out.println("向下搜索");//用来标记警告,如果记事本和搜索框都是空,显示一个就可以了boolean flagWarning = true;//得到文本域中的内容// 1.这个判断首先要放在按钮响应事件里面才会响应// 2.用superString==null/superString==""都不行,我用的是superString.isEmpty()String superString = mainText.getText();if (superString.isEmpty()) {//System.out.println("记事本中的字符串不能为空");warning("记事本中的字符串不能为空");flagWarning = false;}//System.out.println(superString);//获取查询框中的字符串String subString = findText.getText();if (subString.isEmpty()) {//System.out.println("查询框中的字符串不能为空");if (flagWarning) {warning("查询框中的字符串不能为空");flagWarning = false;}}//System.out.println(subString);//要没有出现弹窗才能继续查询,不然就会出现多个弹窗if (flagWarning) {//查找subString出现的位置(往后查找)getSelectionEnd得到光标结束int index = superString.indexOf(subString, findEnd);if (index != -1) {//设置光标开始位置mainText.setSelectionStart(index);//设置光标结束位置mainText.setSelectionEnd(index + subString.length());//保存位置,书写的时候光标也会移动的findStart = index;findEnd = index + subString.length();//获取焦点(不能重新获得焦点,会移动到最后)//mainText.requestFocus();JOptionPane.showMessageDialog(noteFrame.this, "找到匹配的文本");//标记可以替换ableReplace = true;} else {//标记不可以替换JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");ableReplace = false;}}}}});findPreviousButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JButton button = (JButton) e.getSource();//获得触发此次动作事件的按钮对象String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("向上搜索")) {System.out.println("向上搜索");//用来标记警告,如果记事本和搜索框都是空,显示一个就可以了boolean flagWarning = true;//得到文本域中的内容// 1.这个判断首先要放在按钮响应事件里面才会响应// 2.用superString==null/superString==""都不行,我用的是superString.isEmpty()String superString = mainText.getText();if (superString.isEmpty()) {//System.out.println("记事本中的字符串不能为空");warning("记事本中的字符串不能为空");flagWarning = false;}//System.out.println(superString);//获取查询框中的字符串String subString = findText.getText();if (subString.isEmpty()) {//System.out.println("查询框中的字符串不能为空");if (flagWarning) {warning("查询框中的字符串不能为空");flagWarning = false;}}//System.out.println(subString);if (flagWarning) {//查找subString出现的位置(往前查找)int index = superString.lastIndexOf(subString, findStart - 1);if (index != -1) {//设置光标开始位置mainText.setSelectionStart(index);//设置光标结束位置mainText.setSelectionEnd(index + subString.length());//保存位置,书写的时候光标也会移动的findStart = index;findEnd = index + subString.length();//获取焦点(不能重新获得焦点,会移动到最后)//mainText.requestFocus();JOptionPane.showMessageDialog(noteFrame.this, "找到匹配的文本");//标记可以发生替换ableReplace = true;} else {JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");//标记不可以发生替换ableReplace = false;}}}}});cancelButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JButton button = (JButton) e.getSource();//获得触发此次动作事件的按钮对象String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("取消")) {System.out.println("取消");jDialog.dispose();//关闭对话框}}});jDialog.setVisible(true);//让弹窗显示出来}//实现替换条目的功能private void replaceEvent() {System.out.println("替换");//弹窗JDialog jDialog = new JDialog();//创建弹窗对象jDialog.setTitle("替换");//设置弹窗标题,和Frame差不多,可能还要通过标签来提示jDialog.setSize(500, 150);//设置弹窗的大小jDialog.setAlwaysOnTop(true);//让弹窗置顶jDialog.setModal(true);//弹窗不关闭则无法操作下面的界面jDialog.setModal(true);//设置对话框为模式对话框//获取屏幕的宽度和高度int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;//获取JDialog的宽度和高度int dialogWidth = jDialog.getWidth();int dialogHeight = jDialog.getHeight();//计算对话框应该居中显示时的x和y坐标(相对电脑屏幕)int x = (screenWidth - dialogWidth) * 3 / 4;int y = (screenHeight - dialogHeight) / 4;//设置对话框的位置jDialog.setLocation(x, y);//组件信息JTextField findText = new JTextField();JTextField replaceText = new JTextField();JButton findNextButton = new JButton("向下搜索");JButton findPreviousButton = new JButton("向上搜索");JButton cancelButton = new JButton("取消");JButton replaceButton = new JButton("替换");JButton replaceAllButton = new JButton("替换所有");//设置文本框位置和大小findText.setBounds(17, 0, 450, 30);replaceText.setBounds(17, 35, 450, 30);//设置按钮的位置findNextButton.setBounds(10, 70, 90, 27);findNextButton.setFont(new Font("楷体", Font.BOLD, 10));findPreviousButton.setBounds(105, 70, 90, 27);findPreviousButton.setFont(new Font("楷体", Font.BOLD, 10));replaceButton.setBounds(200, 70, 90, 27);replaceButton.setFont(new Font("楷体", Font.BOLD, 10));replaceAllButton.setBounds(295, 70, 90, 27);replaceAllButton.setFont(new Font("楷体", Font.BOLD, 10));cancelButton.setBounds(390, 70, 90, 27);cancelButton.setFont(new Font("楷体", Font.BOLD, 10));//这个也要取消布局管理器才行jDialog.getContentPane().setLayout(null);//往弹窗中添加组件jDialog.getContentPane().add(findText);jDialog.getContentPane().add(replaceText);jDialog.getContentPane().add(findNextButton);jDialog.getContentPane().add(findPreviousButton);jDialog.getContentPane().add(cancelButton);jDialog.getContentPane().add(replaceButton);jDialog.getContentPane().add(replaceAllButton);//绑定事件findNextButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JButton button = (JButton) e.getSource();//获得触发此次动作事件的按钮对象String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("向下搜索")) {System.out.println("向下搜索");//用来标记警告,如果记事本和搜索框都是空,显示一个就可以了boolean flagWarning = true;//得到文本域中的内容// 1.这个判断首先要放在按钮响应事件里面才会响应// 2.用superString==null/superString==""都不行,我用的是superString.isEmpty()String superString = mainText.getText();if (superString.isEmpty()) {//System.out.println("记事本中的字符串不能为空");warning("记事本中的字符串不能为空");flagWarning = false;}//System.out.println(superString);//获取查询框中的字符串String subString = findText.getText();if (subString.isEmpty()) {//System.out.println("查询框中的字符串不能为空");if (flagWarning) {warning("查询框中的字符串不能为空");flagWarning = false;}}//System.out.println(subString);//要没有出现弹窗才能继续查询,不然就会出现多个弹窗if (flagWarning) {//查找subString出现的位置(往后查找)getSelectionEnd得到光标结束//int index = superString.indexOf(subString, replaceEnd);int index = superString.indexOf(subString, findEnd);if (index != -1) {//设置光标开始位置mainText.setSelectionStart(index);//设置光标结束位置mainText.setSelectionEnd(index + subString.length());//保存位置,书写的时候光标也会移动的findStart = index;findEnd = index + subString.length();//replaceStart = index;//replaceEnd = index + subString.length();//获取焦点(不能重新获得焦点,会移动到最后)//mainText.requestFocus();//标记可以替换ableReplace = true;JOptionPane.showMessageDialog(noteFrame.this, "找到匹配的文本");} else {//标记不可以替换ableReplace = false;JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");}}}}});findPreviousButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JButton button = (JButton) e.getSource();//获得触发此次动作事件的按钮对象String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("向上搜索")) {System.out.println("向上搜索");//用来标记警告,如果记事本和搜索框都是空,显示一个就可以了boolean flagWarning = true;//得到文本域中的内容// 1.这个判断首先要放在按钮响应事件里面才会响应// 2.用superString==null/superString==""都不行,我用的是superString.isEmpty()String superString = mainText.getText();if (superString.isEmpty()) {//System.out.println("记事本中的字符串不能为空");warning("记事本中的字符串不能为空");flagWarning = false;}//System.out.println(superString);//获取查询框中的字符串String subString = findText.getText();if (subString.isEmpty()) {//System.out.println("查询框中的字符串不能为空");if (flagWarning) {warning("查询框中的字符串不能为空");flagWarning = false;}}//System.out.println(subString);if (flagWarning) {//查找subString出现的位置(往前查找)//int index = superString.lastIndexOf(subString, replaceStart - 1);int index = superString.lastIndexOf(subString, findStart - 1);if (index != -1) {//设置光标开始位置mainText.setSelectionStart(index);//设置光标结束位置mainText.setSelectionEnd(index + subString.length());//保存位置,书写的时候光标也会移动的findStart = index;findEnd = index + subString.length();//replaceStart = index;//replaceEnd = index + subString.length();//获取焦点(不能重新获得焦点,会移动到最后)//mainText.requestFocus();//标记可以替换ableReplace = true;JOptionPane.showMessageDialog(noteFrame.this, "找到匹配的文本");} else {//标记不可以替换ableReplace = false;JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");}}}}});replaceButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("替换")) {System.out.println("替换");//用来标记警告,如果记事本,搜索框,替换框都是空,显示一个就可以了boolean flagWarning = true;//得到文本域中的内容// 1.这个判断首先要放在按钮响应事件里面才会响应// 2.用superString==null/superString==""都不行,我用的是superString.isEmpty()String superString = mainText.getText();if (superString.isEmpty()) {//System.out.println("记事本中的字符串不能为空");warning("记事本中的字符串不能为空");flagWarning = false;}//System.out.println(superString);//获取查询框中的字符串String formerString = findText.getText();if (formerString.isEmpty()) {//System.out.println("查询框中的字符串不能为空");if (flagWarning) {flagWarning = false;warning("查询框中的字符串不能为空");}}//System.out.println(formerString);//获取替换框中的字符串String newString = replaceText.getText();if (newString.isEmpty()) {//System.out.println("替换框中的字符串不能为空");if (flagWarning) {warning("替换框中的字符串不能为空");flagWarning = false;}}//System.out.println(newString);//要没有出现弹窗才能继续查询,不然就会出现多个弹窗if (flagWarning && ableReplace) {//替换单个好像是要用StringBuilder,String没有这么高级// 只能替换第一个,也可以简化一下程序,每次替换第一个,就不用移动了//这个可以两次的字符串不一样,就是光标指向的字符串和文本框里面不一样String result = superString.substring(findStart, findEnd);//两个一样才能替换if (formerString.equals(result)) {StringBuilder sb = new StringBuilder(superString);//用之前找到的字符串来替换sb.replace(findStart, findEnd, newString);//更新光标的结束位置(开始位置保持不变)findEnd = findStart + newString.length();//更新文本域中的内容retainCursorLocation(sb.toString());JOptionPane.showMessageDialog(noteFrame.this, "成功替换");} else {JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");}} else {JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");}}}});replaceAllButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("替换所有")) {System.out.println("替换所有");//用来标记警告,如果记事本,搜索框,替换框都是空,显示一个就可以了boolean flagWarning = true;//得到文本域中的内容// 1.这个判断首先要放在按钮响应事件里面才会响应// 2.用superString==null/superString==""都不行,我用的是superString.isEmpty()String superString = mainText.getText();if (superString.isEmpty()) {//System.out.println("记事本中的字符串不能为空");warning("记事本中的字符串不能为空");flagWarning = false;}//System.out.println(superString);//获取查询框中的字符串String formerString = findText.getText();if (formerString.isEmpty()) {//System.out.println("查询框中的字符串不能为空");if (flagWarning) {flagWarning = false;warning("查询框中的字符串不能为空");}}//System.out.println(formerString);//获取替换框中的字符串String newString = replaceText.getText();if (newString.isEmpty()) {//System.out.println("替换框中的字符串不能为空");if (flagWarning) {warning("替换框中的字符串不能为空");flagWarning = false;}}//System.out.println(newString);//要没有出现弹窗才能继续查询,不然就会出现多个弹窗if (flagWarning) {//替换所有的字符串String result = superString.replaceAll(formerString, newString);//两个不相同就说明替换成功了,不然就会原样返回if (!superString.equals(result)) {//更新文本域中的内容retainCursorLocation(result);JOptionPane.showMessageDialog(noteFrame.this, "成功替换满足要求的文本");} else {JOptionPane.showMessageDialog(noteFrame.this, "未找到匹配的文本");}}}}});cancelButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JButton button = (JButton) e.getSource();//获得触发此次动作事件的按钮对象String buttonName = e.getActionCommand();//获得触发此次动作事件的按钮的标签文本if (buttonName.equals("取消")) {System.out.println("取消");jDialog.dispose();//关闭对话框}}});jDialog.setVisible(true);//让弹窗显示出来}//输出警告弹窗private void warning(String str) {//添加一个弹窗的警告JDialog jDialog = new JDialog();//创建弹窗对象jDialog.setTitle("警告");//设置弹窗标题,和Frame差不多,可能还要通过标签来提示jDialog.setSize(500, 400);//设置弹窗的大小jDialog.setAlwaysOnTop(true);//让弹窗置顶jDialog.setLocationRelativeTo(null);//让弹窗居中jDialog.setModal(true);//弹窗不关闭则无法操作下面的界面//警告标签,放在弹窗里面final JLabel warningLabel = new JLabel(str, JLabel.CENTER);//设置字体的类型,加粗,和大小warningLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 30));//标签的位置和大小warningLabel.setBounds(0, 100, 500, 100);//这个也要取消布局管理器才行//jDialog.getContentPane().setLayout(null);//往弹窗中添加标签(垂直加居中放置标签)jDialog.getContentPane().add(warningLabel, BorderLayout.CENTER);jDialog.setVisible(true);//让弹窗显示出来}//每次插入文本之后光标会有移动到最后面,所以要保存一下private void retainCursorLocation(String strText) {mainText.setText(strText);mainText.setFont(new Font("楷体", Font.BOLD, 15));//恢复之前的位置mainText.setSelectionStart(findStart);mainText.setSelectionEnd(findEnd);}}

总结

每次都要写很久啊,还是太菜了,本次程序接触到了更多的类,对字符流的输入输出的有了更加清晰的了解,还有字符串的替换和查找,希望未来会更好,因为还有其他事情要忙,所以可能要暂停更新一段时间了。

制作不易,喜欢的小伙伴可以点赞多多支持一下下。

愿大家平安喜乐