加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

【Java】记事本(含剪切、复制、粘贴、全选、撤销)核心设计

(2012-05-12 17:40:54)
标签:

北奕

创意sway工作室

javase

记事本

it

分类: 不需修饰的程序员

前几天我无聊了,随手写了个mini记事本,当然,跟windows系统默认的那个类似,但是没有写得太复杂,基本常用功能都实现了,包括新建文件,打开文件,保存文件,另存为,对文本的剪切,复制,粘贴,全选,撤销功能。对于字体的设置没有做,但是在网上随便找了一下例子,到处都有。当然,记事本这种小软件最核心编码部分还是对文本的编辑操作,也就是剪切复制那些。

http://s6/bmiddle/4b20ae2egbfd3ab990e65&690


 

实现要什么控件,我想应该不用再讨论了。打开文件要用到一个类FileDialog,可以设置它的mode来决定它的功能。比如下面这个是实现打开功能,mf这里是指frame,因为我这个打开文件操作是封装在控制器类的一个方法中,所以传的是界面对象。如果把这个写在主界面那就要改成thisFileDialog.LOAD就是mode的其中一种,有什么选项可以看看API,这里是加载文件,也就是打开文件的功能。

FileDialog file= newFileDialog(mf,"打开",FileDialog.LOAD);

file.setVisible(true);

可以通过file.getDirectory()获取路径,file.getFile()获取文件名。保存和另存为也一样,通过mod来改变FileDialog的功能。打开文件需要用的是对文件的读入方式,保存文件用的是对文件的写出方式,也就是IO流。对文件的读写方式有很多种,但是要注意的是编码问题。有人或许会发现怎么用自己写的记事本保存了文件后再用windows默认的记事本打开,排版有点不对,这个是编码问题引起的。Windows默认的记事本编码只有四种,而我们自己写的程序编码方式默认为项目的编码方式,如果想要给它以特定的编码方式打开,可以使用InputStreamReaderOutputStreamWritter对文件读写。以下是以逐行读取字符流来读取文件:

          FileInputStream fs = new FileInputStream(txt);

          InputStreamReader inReader = newInputStreamReader(fs,"UTF-8");

          BufferedReader br = newBufferedReader(inReader);

          String str;

          while((str=br.readLine())!=null){

              mf.body.append(str+"\n");

         

          br.close();

对文本的编辑功能需要用到Clipboard类,也就是剪贴板。通过clipboard = getToolkit().getSystemClipboard();获取系统的剪贴板,也就当系统剪贴板上有内容的时候,同样可以被用到自己编写的记事本软件中。复制操作,如下代码:

public void copy(){

       //拖动选取文本

       String temp = mf.body.getSelectedText();

       //把获取的内容复制到连续字符器,这个类继承了剪贴板接口

       StringSelection text = new StringSelection(temp);

       //把内容放在剪贴板

       mf.clipboard.setContents(text, null);

}

我的mf.body是指主只界面上的名字叫bodyJTextArea控件。剪切内容跟复制类似,在复制的基础之上再加三行代码:

//标记开始位置

int start = mf.body.getSelectionStart();

//标记结束位置

int end = mf.body.getSelectionEnd();

//删除所选段

mf.body.replaceRange("", start, end);

最复杂的粘贴来了,我看了一些人写这个功能写得很简陋,还有bug,没有考虑到当要粘贴的时候鼠标已经选中了一部分内容。当然,要粘贴之前还是先要判断一下剪贴板里面有没有内容,如果没有当然贴不出什么东西。所以,我就把粘贴这个功能写成:

public void paste(){

          //Transferable接口,把剪贴板的内容转换成数据

          Transferable contents = mf.clipboard.getContents(this);

          //DataFalvor类判断是否能把剪贴板的内容转换成所需数据类型

          DataFlavor flavor = DataFlavor.stringFlavor;

          //如果可以转换

          if(contents.isDataFlavorSupported(flavor)){

              String str;

              try {//开始转换

                 str=(String)contents.getTransferData(flavor);

                 //如果要粘贴时,鼠标已经选中了一些字符

                 if(mf.body.getSelectedText()!=null){

                     //定位被选中字符的开始位置

                     int start = mf.body.getSelectionStart();

                     //定位被选中字符的末尾位置

                     int end = mf.body.getSelectionEnd();

                     //把粘贴的内容替换成被选中的内容

                     mf.body.replaceRange(str, start, end);

                 }else{

                     //获取鼠标所在TextArea的位置

                     int mouse = mf.body.getCaretPosition();

                     //在鼠标所在的位置粘贴内容

                     mf.body.insert(str, mouse);

                 }

                

              } catch(UnsupportedFlavorException e) {

                 e.printStackTrace();

              } catch (IOException e) {

                 e.printStackTrace();

              } catch(IllegalArgumentException e){

                 e.printStackTrace();

              }

          }

}

全选是最简单的,body.selectAll()函数就能搞定。在没有做这个小软件之前,我也没有接触过怎么做撤销功能的,但是查了一下API发现了UndoManager这个类,而且操作非常简单。初始化一个UndoManger,然后通过body.getDocument().addUndoableEditListener(undoMgr)这个方法,就可以把撤销管理器的监听器添加到TextArea中。需要调用撤销的时候就调用unoMgr.undo()方法。

我还做了鼠标的右击弹出一个菜单对文本进行编辑。右击弹出的菜单叫JPopupMenu,然后往里面添加JMenuItem控件。Java的鼠标事件是没有右击事件或者双击事件的,需要自己定义。默认鼠标点击事件,不管你点击的是左键还是右键,事件都会被响应,不信你可以试试(按钮响应的鼠标点击事件除外)。想要在点击TextArea中点击右键就弹出菜单,可以在给TextArea添加鼠标监听器,在响应函数中添加判断if(mouseEven.getButton()==3),为真就是鼠标的右击事件。

除了使用JTextArea控件实现文本编辑,还有一个更方便的的JTextPane。这个控制直接就定义了复制,剪切,粘贴函数,需要用的时候直接调用就行,不需要在自己编写剪贴板的代码,它已经有这些功能了。添加撤销的方法跟JTextArea一致。不知道是不是我没找到FileDialog的返回值,还有一个比FileDialog更好使含有返回值的控件JFileChooserJFileChooser的默认路径是系统登陆用户的“我的文档”目录下,如果要修改这个路径,可以通过setCurrentDirectory()修改。先苦后甜,两种方式不妨试试。

在功能逻辑的核心设计,那就是要判断每次用户要打开新文件或者是准备离开之前是否编辑了,如果被编辑了就要提示是否保存。另存为文件的时候,如果是文件名字相同,要提示是否要覆盖文件。

此代码已经开源(切勿用于谋利):https://github.com/arjinmc/MiniNotePad 

可执行文件我上传到网上,大家可以看看效果。http://ishare.iask.sina.com.cn/f/24401037.html

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有