Java实现简易文本编辑器

数据结构课设要求完成一个简易文本编辑器,以下记录完成过程中的思路,学习到的新知识,遇到的问题和解决方案等。

要求至少实现以下要求:
1)具有图形菜单界面
2)查找,替换(等长, 不等长),插入(插串,文本块的插入)、快移动(行块,列块移动),删除
3)可正确存盘、取盘
4)正确显示总行数

新学到的方法:

  • ActionEvent 的 getSource()
    继承自 EventObject;返回最初发生 Event 的对象。

  • public int getlineofoffset(int offset) throws badlocationexception
    将文本中的偏移量offset转化为行号

  • public int getCaretPosition()
    返回文本插入符的位置。插入符的位置被限制在 0 和文本最后一个字符(包括)之间。如果没有设置文本或插入符,则默认插入符的位置为 0。

  • indexOf() 方法有以下四种形式:
    public int indexOf(int ch): 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。
    public int indexOf(int ch, int fromIndex): 返回从 fromIndex 位置开始查找指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回-1。
    int indexOf(String str): 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。
    int indexOf(String str, int fromIndex): 返回从 fromIndex 位置开始查找指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1
    同样的,还有lastIndexOf()返回最后一次出现的位置,反向搜索

  • getDocument()
    Java实现简易文本编辑器_第1张图片

  • public component getfocusowner()
    如果此窗口为焦点窗口,则返回是焦点窗口的子组件;
    否则(即该窗口不是焦点窗口)返回 null。

  • public boolean isfocused()
    返回:此窗口是否为焦点窗口。如果存在焦点所有者,则焦点窗口就是(或者包含)焦点所有者的窗口。如果不存在焦点所有者,则没有作为焦点的窗口。
    如果焦点窗口是一个 frame 或 dialog,那么它同时也是一个活动窗口。否则,活动窗口将是拥有焦点窗口的第一个 frame 或 dialog。

出现的问题及解决方案

  • 使用BufferedReader出现中文乱码的情况
    解决:文件保存的时候设置编码为“ANSI”
    Java实现简易文本编辑器_第2张图片

  • 完成选择文本用键盘的左右键实现左右移动的时候

						  input.replaceSelection("");
						  String text = input.getText();
						  text = text.substring(0,position)+sText+text.substring(position,text.length());
						  input.setText(text);
						  input.setCaretPosition(position+sText.length()-1);
						  input.select(input.getCaretPosition()-sText.length()+1, input.getCaretPosition()+1);

我想要实现可以持续进行左右移动的效果,也就是触发键盘监听器实现左/右移动后仍然选择该文本,使用input.select(…)其中input是JTextArea文本输入区域,但是出现的状况是文本并没有被选择中,但是通过调试可以发现文本是被选择了的只是没有被高亮,因此思路转到焦点上,可以发现JTextArea是焦点Componet,但该窗口不是焦点窗口(getFocusOwner()==null)。但是加入System.out.println(getFocusOwner().getX());会报NullPointerException,但是也能实现窗口聚焦的功能,现在还没解决问题。

完成思路

  • 需要动态地获取当前光标所在位置
input.addCaretListener(new CaretListener() {
     
			
			@Override
			public void caretUpdate(CaretEvent e) 
			{
     
				JTextArea editArea = (JTextArea)e.getSource();
				int lineNum = 1;
				int columnNum = 1;
				try
				{
     
                    int caretpos = editArea.getCaretPosition();
                    //获取当前光标偏移量
                    lineNum = editArea.getLineOfOffset(caretpos);
                    //获取当前光标所在位置的行偏移量
                    columnNum = caretpos - editArea.getLineStartOffset(lineNum);
                    //当前光标所在的列位置就是caretpos-这一行最初的列偏移量
                    lineNum += 1;
                    //然后再将行的数目加1(从0开始计算偏移量)
                }
                catch(Exception ex) {
      }
                updateStatus(lineNum, columnNum);
                //updateStatus是更新状态栏的方法
			}
		});
  • 需要正确的获取文本内容的总行数
    不能凭借光标的位置来判断总行数,应该以最后有内容的一行的行数来作为文本内容的总行数。记录光标到达过的最大行数maxCaretLine,从这一行开始判断,如果这一行为空,则再往上一行判断,如果这一行不为空,则为最后有内容的一行的行数。最初想到的判断方法是
for(int i = maxCaretLine;i >= 0;i --)
				{
     
					 String value = input.getText().split("\r\n")[i];
					 if(value != null)
					 {
     
						 line = i;
						 break;
					 }
				}

但在换行的时候出现了问题,如果以分隔符来判断,换行后本来maxCaretLine应该等于2了,但是由于换行后用分隔符分割开的数组大小仍然为1(此时换行后还未新增内容)并且中间无论跳多少行都算作一行,所以改用BufferReader来读取每一行

  • 打开和保存文件的选择路径方法我最开始使用的是JFileChooser
int result = 0;
				String path = null;
				JFileChooser fileChooser = new JFileChooser();
				FileSystemView fsv = FileSystemView.getFileSystemView(); 
				System.out.println(fsv.getHomeDirectory()); 
				fileChooser.setCurrentDirectory(fsv.getHomeDirectory());
				fileChooser.setDialogTitle("打开");
				fileChooser.setApproveButtonText("确定");
				fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
				fileChooser.addChoosableFileFilter(new FileFilter()
				{
      
					@Override
					public String getDescription() {
     
				        return "文本文件";     
					}
					
					@Override
					public boolean accept(File f) {
     
						if (f.getAbsolutePath().endsWith(".txt") || f.isDirectory())     
				            return true;     
						return false;
					}
				});
				result = fileChooser.showOpenDialog(openning);

但是后来找到了FileDialog(觉得更好看qaq)

  • 文本筛选器:筛选出文本文件
fileChooser.addChoosableFileFilter(new FileFilter()
{
      
					@Override
					public String getDescription() {
     
				        return "文本文件";     
					}
					
					@Override
					public boolean accept(File f) {
     
						if (f.getAbsolutePath().endsWith(".txt") || f.isDirectory())     
				            return true;     
						return false;
					}
				}); 
					 
				 

但是FileDialog对上面的方法不适用,并没有适用。jdoc的原注释为:Filename filters do not function in Sun’s reference implementation for Microsoft Windows.
所以就换了一种比较通俗的方法

FileDialog also = new FileDialog(openning,"另存为",FileDialog.SAVE);
also.setFile("*.txt;");

直接将要查找的文件名设置为*.txt,就可以直接找到以txt为后缀的文件了。
暂时还没有找到更合适的筛选器。
Java实现简易文本编辑器_第3张图片

  • 实现移动整行和整列的效果:
    思路:【数组】需要标识行数和列数——【二维数组】将每一行的数据保存在一个数组中,每一行用“\n”分割开为数组,每一行的字串再用“”分开,形成二维数组:
					String s = input.getText();
					String[][] a;
					String[] sFirst=s.split("\n");
					a=new String[sFirst.length][];		
					//sFirst.length表示有多少行
					for(int i=0;i<sFirst.length;i++)
					{
     
						String[] sSecond= sFirst[i].split("");		
						a[i]=new String[sSecond.length];
						//sSecond.length分别表示每一行有多少列
						for(int j=0;j<sSecond.length;j++)
						{
     
							a[i][j] = sSecond[j];
							if(maxColumn < a[i].length)
								maxColumn = a[i].length;
						}
					}					

但在进行移动的时候,例如将第2行移动到第7行,那么第3-7行都要上移

							String[] usedString = a[used-1];
							int i = used;
							for(;i < after; i++)
							{
     
								a[i-1] = a[i]; 
							}
							d[after-1] = usedString;

如果行数间隔大的话,for循环的时间就更长了,显然没有链表方便,【二维链表】将每一行的数据保存在一个单向链表中,将每一行的表头保存在一个行链表中形成一个二维链表,这样在移动的时候只需要更改一项就可以了。

你可能感兴趣的:(java)