自上半年JAVA课程结束后,再也没有看过JAVA了,最近不是很忙,又简单的看了看,本博客纯属记录学习过程,请大神们别笑,其中错误是难免的,毕竟是新手写的博客。下面就进入我们的正题吧,复习GUI时,就想到WINDOWS的记事本,如果用GUI来仿写应该不难。实现向记事本这样的文本编辑器,第一步,当然是界面的问题,这对于GUI来说再简单不过了,所以我也不多说了,直接贴上代码即可,相信都能看懂。
创建菜单代码:
1 //创建主菜单
2 public voidcreateMenu()3 {4 //创建JMenuBar菜单条
5 mainMenuBar=newJMenuBar();6 //创建四个JMenu下拉菜单
7 fileMenu=new JMenu("文件(F)");8 editMenu=new JMenu("编辑(E)");9 formatMenu=new JMenu("格式(O)");10 viewMenu=new JMenu("查看(V)");11 helpMenu=new JMenu("帮助(H)");12 //创建JMenuItem并添加到对应的JMenu中
13 mainMenuBar.add(fileMenu);14 newItem=new JMenuItem("新建");15 openItem=new JMenuItem("打开..");16 saveItem=new JMenuItem("保存..");17 saveasItem=new JMenuItem("另存为..");18 pageItem=new JMenuItem("页面设置..");19 printItem=new JMenuItem("打印..");20 exitItem=new JMenuItem("退出");21 fileMenu.add(newItem);22 fileMenu.add(openItem);23 fileMenu.add(saveItem);24 fileMenu.add(saveasItem);25 fileMenu.addSeparator();26 fileMenu.add(pageItem);27 fileMenu.add(printItem);28 fileMenu.addSeparator();29 fileMenu.add(exitItem);30
31 mainMenuBar.add(editMenu);32 undoItem=new JMenuItem("撤消");33 cutItem=new JMenuItem("剪切");34 copyItem=new JMenuItem("复制");35 pasteItem=new JMenuItem("粘贴");36 findItem=new JMenuItem("查找..");37 replaceItem=new JMenuItem("替换..");38 selectallItem=new JMenuItem("全选");39 dateItem=new JMenuItem("时间/日期");40 editMenu.add(undoItem);41 editMenu.addSeparator();42 editMenu.add(cutItem);43 editMenu.add(copyItem);44 editMenu.add(pasteItem);45 editMenu.addSeparator();46 editMenu.add(findItem);47 editMenu.add(replaceItem);48 editMenu.addSeparator();49 editMenu.add(selectallItem);50 editMenu.add(dateItem);51 mainMenuBar.add(formatMenu);52 wrapItem=new JCheckBoxMenuItem("自动换行");53 fontItem=new JMenuItem("设置字体..");54 formatMenu.add(wrapItem);55 formatMenu.add(fontItem);56 mainMenuBar.add(viewMenu);57 mainMenuBar.add(helpMenu);58 helpItem=new JMenuItem("查看帮助(H)");59 aboutItem=new JMenuItem("关于记事本..(A)");60 helpMenu.add(helpItem);61 helpMenu.add(aboutItem);62 //为每个菜单项添加监听器
63 exitItem.addActionListener(this);64 saveItem.addActionListener(this);65 saveasItem.addActionListener(this);66 newItem.addActionListener(this);67 printItem.addActionListener(this);68 openItem.addActionListener(this);69 cutItem.addActionListener(this);70 copyItem.addActionListener(this);71 pasteItem.addActionListener(this);72 selectallItem.addActionListener(this);73 dateItem.addActionListener(this);74 wrapItem.addActionListener(this);75 findItem.addActionListener(this);76 fontItem.addActionListener(this);77 helpItem.addActionListener(this);78 aboutItem.addActionListener(this);79 }
View Code
下面继续看看每个菜单的具体响应和实现。
1."新建"功能的实现:
当使用者点击“新建”菜单时,首先要判断文件中的内容是否改变过,如果修改过,则询问使用者是否要保存修改,并且根据选择做出相应的动作,如果用户选择“是“,则保存修改后的文件,否则保存原来的文档。具体代码如下:
1 voiddoNewFile()2 {3 intselect,flag;4 if (changed)//判断文件内容是否修改过
5 {6 select=JOptionPane.showConfirmDialog(this,"文件修改后尚未存盘,要保存吗?");7 switch(select)8 {9 caseJOptionPane.YES_OPTION:10 flag=doSave();11 break;12 caseJOptionPane.NO_OPTION:13 flag=1;14 break;15 default:16 flag=0;17 break;18 }19 }20 else
21 {22 flag = 1;23 }24 if(flag==1)//新建文件,并设置内容为空
25 {26 changed=false;27 haveName=false;28 setTitle("无名称——记事本");29 text.setText(null);30 }31 }
View Code2
2.“打开”功能的实现:
当用户选择“打开”菜单时,首先判断文件内容是否修改过,若修改过,则询问是否保存,若用户选择“是”,则弹出保存窗口,否则弹出一个文件选择对话框由使用者选择要打开的文件,并且读入选择的文件的内容并复制给text。具体代码如下:
1 voiddoOpenFile()2 {3 intselect,flag;4 File tmpfile=null;5 ExampleFileFilter filter;6 JFileChooser chooser;7 FileInputStream fin;8 bytebuf[];9 //判断文件内容是否修改过并询问是否存盘
10 if(changed)11 {12 select=JOptionPane.showConfirmDialog(this,"文件已修改,是否要保存?");13 switch(select)14 {15 caseJOptionPane.YES_OPTION:16 flag=doSave();17 break;18 caseJOptionPane.NO_OPTION:19 flag=1;20 break;21 default:22 flag=0;23 break;24 }25 }26 else
27 {28 flag = 1;29 }30 //当前文件处理完毕,准备打开一个文件
31 if(flag==1)32 {33 changed = false;34 //设置文件类型过滤器
35 filter = newExampleFileFilter();36 filter.addExtension("txt");37 filter.setDescription("文本文件");38 //模拟记事本设置默认打开路径
39 if (file!=null)40 chooser = newJFileChooser(file.getPath());41 else
42 chooser = newJFileChooser();43 chooser.setFileFilter(filter);44 select = chooser.showOpenDialog(this);45 if(select ==JFileChooser.APPROVE_OPTION)46 {47 tmpfile=chooser.getSelectedFile();//使用文件流读入文件类容
48 try
49 {50 fin=newFileInputStream(tmpfile);51 buf=new byte[(int)tmpfile.length()];52 fin.read(buf);53 fin.close();54 text.setText(new String(buf));//实现内容的现实
55 changed=false;56 haveName=true;57 file=tmpfile;58 setTitle("记事本 -- "+file.getName());59 }catch(FileNotFoundException e)60 {61 JOptionPane.showMessageDialog(this,"指定的文件名称或属性有问题!");62 }catch(IOException e)63 {64 JOptionPane.showMessageDialog(this,"无法读文件,请检查文件是否被锁定");65 }66 }67 }68 }
View Code3
运行截图:
3.保存功能的实现:
当使用者点击“保存”菜单时,需要完成如下事情:第一、判断文件是否为新建的文件,如果是,则调用doSaveAs()来保存;否则,判断原文件内容是否发生修改,若修改过,再询问用户是否另存,否则不做任何动作。具体代码如下:
1 //保存使用者编辑的文件,保存成功返回1,否则返回0
2 intdoSave()3 {4 FileOutputStream fout;5 bytecontent[];6 intflag;7 if (!haveName)//判断是否新建的文件
8 {9 flag =doSaveAs();10 }11 else if(changed)//判断内容是否发生修改
12 {13 try
14 {15 fout=newFileOutputStream(file);16 content=text.getText().getBytes();17 fout.write(content);18 fout.close();19 changed=false;20 flag = 1;21 }catch(FileNotFoundException e)//进行相应异常处理
22 {23 JOptionPane.showMessageDialog(this,"指定的文件名称或属性有问题!");24 flag = 0;25 }catch(IOException e)26 {27 JOptionPane.showMessageDialog(this,"无法写文件,请检查文件是否被锁定");28 flag = 0;29 }30 }31 else
32 {33 flag =1;34 }35 returnflag;36 }
4.实现“另保存”功能:
当使用者选择“另存为”菜单时,打开一个保存对话框,让使用者选择保存路径和文件名,如果文件名已存在,则弹出一个警告框,让使用者选择是否覆盖文件。否则以用户填写的文件名来保存文件并更改相关变量。
为了实现这些功能,需要用到JFileChooser类和ExampleFileFilter类。而ExampleFileFilter类并不是JAVA标准库的类,所以必须将它引入的项目中,有关于相关的配置就不介绍了,网上有很多资料。同时,由于要处理用户的输入,因此需要大量的代码来提高容错率即程序的健壮性。具体代码如下:
1 //用"另存为"对话框保存文件。保存成功返回1,否则返回0
2 intdoSaveAs()3 {4 FileOutputStream fout;5 bytecontent[];6 int flag=0;7 File tmpfile=null;8 ExampleFileFilter filter = newExampleFileFilter();9 JFileChooser chooser;10 filter.addExtension("txt");//设置保存文件对话框中的文件属性过滤器
11 filter.setDescription("文本文件");12 if (file!=null)13 chooser = newJFileChooser(file.getPath());14 else
15 chooser = newJFileChooser();16 chooser.setFileFilter(filter);//设置文件类型
17 flag = chooser.showSaveDialog(this);18 if(flag ==JFileChooser.APPROVE_OPTION)19 {20 tmpfile=chooser.getSelectedFile();21 if (tmpfile.exists())//判断同名同类文件是否已存在
22 {23 if (JOptionPane.showConfirmDialog(this,"文件已经存在,是否覆盖?",24 "警告",JOptionPane.YES_NO_OPTION)==JOptionPane.YES_OPTION)25 {26 flag=1;27 }28 else
29 {30 flag=0;31 }32 }33 else
34 {35 flag=1;36 }37 }38 else
39 {40 flag=0;41 }42
43 if (flag==1)44 {//用户已经确定要以指定名称保存文件
45 try
46 {47 fout=newFileOutputStream(tmpfile);48 content=text.getText().getBytes();49 fout.write(content);50 fout.close();51 flag = 1;52 }catch(FileNotFoundException e)53 {54 JOptionPane.showMessageDialog(this,"指定的文件名称或属性有问题!");55 flag = 0;56 }catch(IOException e)57 {58 JOptionPane.showMessageDialog(this,"无法写文件,请检查文件是否被锁定");59 flag = 0;60 }61 }62
63 if (flag==1)64 {//文件保存成功,修改相关变量
65 changed=false;66 haveName=true;67 file=tmpfile;68 this.setTitle(file.getName()+"——记事本");69 }70 returnflag;71 }
5.“打印”菜单功能的相应:
JAVA中关于打印API主要存在于java.awt.print包中,但是,在此我们使用JDK1.4新增的javax.print包和其相应子包javax.print.event和javax.print.attribute中的类来实现打印功能。其中,javax.print包中的主要包括打印服务的相关类,而javax.print.evevt则包含打印事件的相关定义,javax.print.attribute则包括打印服务的可用属性列表等。
要实现打印功能,步骤如下:
定位到一台打印机
指定要打印的格式
设置打印属性
设置打印内容
开始打印
具体代码如下:
1 //调用打印对话框,给用户打印文档
2 voiddoPrint()3 {4 try{5 //构建打印属性集
6 PrintRequestAttributeSet pras = newHashPrintRequestAttributeSet();7 //设置打印格式
8 DocFlavor flavor =DocFlavor.BYTE_ARRAY.AUTOSENSE;9 //查找所有的可用打印服务
10 PrintService printService[] =PrintServiceLookup.lookupPrintServices(flavor, pras);11 PrintService defaultService =PrintServiceLookup.lookupDefaultPrintService();12 //显示打印对话框
13 PrintService service = null;14 service = ServiceUI.printDialog(null, 100, 100, printService, defaultService, flavor, pras);15 if (service!=null)//16 {17 //创建打印作业
18 DocPrintJob job =service.createPrintJob();19 DocAttributeSet das = newHashDocAttributeSet();20 //建立打印文件格式
21 Doc doc = newSimpleDoc(text.getText().getBytes(), flavor, das);22 //进行文件的打印
23 job.print(doc, pras);24 }25 }catch(Exception e)26 {27 JOptionPane.showMessageDialog(this,"打印任务无法完成");28 }29 }
6."退出功能的实现"
关于这个功能比较简单,但是需要注意一个问题,当点击窗体右上不得关闭按钮时,也需要作出相应的响应,而不是直接退出,因此,在程序中需要覆盖JFrame的窗口关闭方法processWindowEvent(注意:这里不是监听windowsClosing事件)。具体代码如下:
protected voidprocessWindowEvent(WindowEvent e)
{if (e.getID() ==WindowEvent.WINDOW_CLOSING)
doExit();
}
//程序退出时的代码
voiddoExit()
{intselect;if (!changed) //判断文件是否发生改变
System.exit(0);else{
select=JOptionPane.showConfirmDialog(this,"文件修改后尚未存盘,要保存吗?");switch(select)
{caseJOptionPane.YES_OPTION:
select=doSave();if (select==1)System.exit(0);break;caseJOptionPane.NO_OPTION:
System.exit(0);break;caseJOptionPane.CANCEL_OPTION:break;
}
}
}
7.“剪切”功能的实现:
为了完成这一功能,应该为文本框添加两个监听器:键盘事件监听器KeyListener和鼠标事件监听器MouseListener。并且实现其中的keyPressed和mouseRealseed方法就可以了。这里我们采用继承相应的适配器类KeyAdapter和MouseAdapter即可。这部分相当简单,就不多说了。下面是具体代码:
//监听鼠标事件
class handleMouse extendsMouseAdapter
{public voidmouseReleased(MouseEvent e)
{
chkText();
}
}//监听键盘事件
class handleKey extendsKeyAdapter
{public voidkeyPressed(KeyEvent e)
{
chkText();
}
}//根据用户选择文本的情况,修改菜单的状态
voidchkText()
{if(text.getSelectedText()==null)
{
cutItem.setEnabled(false);
copyItem.setEnabled(false);
}else{
cutItem.setEnabled(true);
copyItem.setEnabled(true);
}
}//将用户选择的文本剪切到剪贴板
voiddoCut(){
text.cut();
}
8.实现查找功能:
由于该部分功能JDK并没有提供查找对话框,我就模仿Windows的记事本啦。代码如下:
1 import java.awt.*;2 import java.awt.event.*;3 import javax.swing.*;4
5 public class findDialog extends JDialog implementsActionListener6 {7 Container con;8 JPanel panel1,panel2;9 JTextArea text;10 JLabel label1;11 JTextField findEdit;12 JCheckBox checkBox;13 JRadioButton upBtn,downBtn;14 ButtonGroup dirBtnGroup;15 JButton OKBtn,CancleBtn;16
17 intstart;18 publicfindDialog(JFrame owner, JTextArea Jtext)19 {20 super(owner,false);21 start=0;22 text=Jtext;23 panel1=newJPanel();24 panel1.setLayout(newFlowLayout());25 panel2=newJPanel();26 panel2.setLayout(newFlowLayout());27
28 label1=new JLabel("查找内容");29 findEdit=new JTextField(12);30 OKBtn=new JButton("查找下一个");31 OKBtn.addActionListener(this);32 panel1.add(label1);33 panel1.add(findEdit);34 panel1.add(OKBtn);35
36 checkBox=new JCheckBox("区分大小写");37 checkBox.setSelected(true);38 upBtn=new JRadioButton("向上");39 downBtn=new JRadioButton("向下",true);40 dirBtnGroup=newButtonGroup();41 dirBtnGroup.add(upBtn);42 dirBtnGroup.add(downBtn);43 CancleBtn=new JButton("取消");44 CancleBtn.addActionListener(this);45 panel2.add(checkBox);46 panel2.add(upBtn);47 panel2.add(downBtn);48 panel2.add(CancleBtn);49
50 con=getContentPane();51 con.setLayout(newFlowLayout());52 con.add(panel1);53 con.add(panel2);54 setTitle("查找");55 setSize(300,120);56 setVisible(true);57 }58
59 public voidactionPerformed(ActionEvent e)60 {61 if (e.getSource()==OKBtn)62 {63 find(e);64 }65 else
66 {67 dispose();68 }69 }70 public voidfind(ActionEvent e)71 {72 intindex;73 if (start>text.getCaretPosition())74 start=text.getCaretPosition();75 //区分大小写查找
76 if((e.getSource()==checkBox)&&(checkBox.isSelected()==true))77 {78 index=text.getText().indexOf(findEdit.getText(),start);79 IndexNum(index);80 }//不区分大小写查找
81 else if((e.getSource()==checkBox)&&(checkBox.isSelected()==false))82 {83 index=text.getText().toUpperCase().indexOf(findEdit.getText().toUpperCase(),0);84 IndexNum(index);85 }86 }87 public void IndexNum(intindex)88 {89 if (index<0)90 {91 JOptionPane.showMessageDialog(this,"查找完毕");92 start=0;93 }94 else
95 {96 text.setSelectionStart(index);97 text.setSelectionEnd(index+findEdit.getText().length()-1);98 start=index+findEdit.getText().length();99 }100 }101
102 }
View Code
运行截图如下:
9.实现社字体功能
对于这一部分功能,JDK并没有提供相应的设置对话框,因此,依旧仿照Windows提供的标准字体选择对话框来制作。对于此问题涉及到如何获取系统中的字体名称并显示在一个列表框中,再者如何将用户设置的字体字形和大小组合成一个Font对象返回给用户。对于界面,就模仿Windows的记事本界面,但是,在此处涉及到布局的问题,我就采用了表格布局和流式布局。
代码如下:
//设置字体
voiddoChangeFont()
{if(myFontDialog==null)
myFontDialog=new fontDialog(this);if(myFontDialog.showFontDialog()==fontDialog.OK)
text.setFont(myFontDialog.getFont());
}
1 import java.awt.event.*;2 import javax.swing.*;3 import javax.swing.event.*;4 import java.awt.*;5
6 public class fontDialog extends JDialog implementsActionListener,ListSelectionListener7 {8 public static final int Cancle=0;9 public static final int OK=1;10 public static final String [] style={"正常","斜体","粗体","粗斜体"};11 public static final String [] size={"8","9","10","11","12","14","16",12 "18","20","22","24","26","28","36","48","72"};13 //用于记录用户设置的字体信息
14 private Font userFont=null;15 //标记用户按下的按钮
16 private int userSelect=Cancle;17 //窗体的父窗体
18 private JFrame parent=null;19 privateContainer con;20 privateJScrollPane nameSPane,styleSPane,sizeSPane;21 privateJPanel panel[];22 privateJLabel nameLbl,styleLbl,sizeLbl;23 privateJTextField nameText,styleText,sizeText;24 privateJList nameList,styleList,sizeList;25 privateJButton OKBtn,cancleBtn;26
27 publicfontDialog()28 {29 this(null);30 }31
32 publicfontDialog(JFrame owner)33 {34 super(owner,true);35 parent=owner;36 setTitle("字体");37 con=getContentPane();38 BoxLayout box=newBoxLayout(con,BoxLayout.Y_AXIS);39 con.setLayout(box);40 panel=new JPanel[4];41 for(int i=0;i<3;i++)42 {43 panel[i]=newJPanel();44 panel[i].setLayout(new GridLayout(1,3));45 }46 panel[3]=newJPanel();47 panel[3].setLayout(newFlowLayout());48
49 nameLbl=new JLabel("字体");50 styleLbl=new JLabel("字形");51 sizeLbl=new JLabel("大小");52 panel[0].add(nameLbl);53 panel[0].add(styleLbl);54 panel[0].add(sizeLbl);55
56 nameText=new JTextField("宋体");57 nameText.setColumns(5);58 nameText.setEditable(false);59 styleText=new JTextField("正常");60 styleText.setColumns(5);61 styleText.setEditable(false);62 sizeText=new JTextField("12");63 sizeText.setColumns(5);64 sizeText.setEditable(false);65 panel[1].add(nameText);66 panel[1].add(styleText);67 panel[1].add(sizeText);68 //获取系统所安装的字体的名称
69 GraphicsEnvironment eq =GraphicsEnvironment.getLocalGraphicsEnvironment();70 String[] availableFonts=eq.getAvailableFontFamilyNames();71 nameList=newJList(availableFonts);72 nameList.addListSelectionListener(this);73 nameSPane=newJScrollPane(nameList);74 styleList=newJList(style);75 styleList.addListSelectionListener(this);76 styleSPane=newJScrollPane(styleList);77 sizeList=newJList(size);78 sizeList.addListSelectionListener(this);79 sizeSPane=newJScrollPane(sizeList);80 panel[2].add(nameSPane);81 panel[2].add(styleSPane);82 panel[2].add(sizeSPane);83
84 OKBtn=new JButton("确定");85 OKBtn.addActionListener(this);86 cancleBtn=new JButton("取消");87 cancleBtn.addActionListener(this);88 panel[3].add(OKBtn);89 panel[3].add(cancleBtn);90
91 for(int i=0;i<4;i++)92 con.add(panel[i]);93 }94
95 public intshowFontDialog()96 {97 setSize(300,300);98 intx,y;99 if (parent!=null)100 {101 x=parent.getX()+30;102 y=parent.getY()+30;103 }104 else
105 {106 x=150;107 y=100;108 }109 setLocation(newPoint(x,y));110 setVisible(true);111 returnuserSelect;112 }113
114 publicFont getFont()115 {116 returnuserFont;117 }118
119 public voidactionPerformed(ActionEvent e)120 {121 int styleIndex=Font.PLAIN,fontSize;122 if(e.getSource()==OKBtn)123 {124 if(styleText.getText().equals("正常"))125 styleIndex=Font.PLAIN;126 if(styleText.getText().equals("斜体"))127 styleIndex=Font.ITALIC;128 if(styleText.getText().equals("粗体"))129 styleIndex=Font.BOLD;130 if(styleText.getText().equals("粗斜体"))131 styleIndex=Font.BOLD |Font.ITALIC;132 fontSize=Integer.parseInt(sizeText.getText());133 userFont=newFont(nameText.getText(),styleIndex,fontSize);134 userSelect=OK;135 setVisible(false);136 }137 else
138 {139 userSelect=Cancle;140 setVisible(false);141 }142 }143
144 public voidvalueChanged(ListSelectionEvent e)145 {146 if (e.getSource()==nameList)147 nameText.setText((String)nameList.getSelectedValue());148 if (e.getSource()==styleList)149 styleText.setText((String)styleList.getSelectedValue());150 if (e.getSource()==sizeList)151 sizeText.setText((String)sizeList.getSelectedValue());152 }153 }
View Code
运行截图:
10.其他功能:
弹出式菜单
//创建弹出式菜单
public voidcreatePopupMenu()
{
popMenu=newJPopupMenu();
popMenu.add("撤消");
popMenu.addSeparator();
popMenu.add("剪切");
popMenu.add("复制");
popMenu.add("粘贴");
popMenu.addSeparator();
popMenu.add("全选");
}
然后用setComponentPopupMenu()为文本去加上这个菜单即可。
至于复制、粘贴、全选、替换、获取时间/日期和自动换行等功能比较简单,就不累述了。
本博客是参考相关的java资料,我们在大学学了很多种语言,要尝试着用不同的语言来实现,虽然思路是一样的,但是实现的过程中还是有相当部分不同的。当然,本例只是给出了纯文本编辑器,不能进行其他方面操作。其实本人也在想如果我们将编译原理的知识加进来,实现某种简单语言(如:PL/0语言)的词法分析、语法分析、语义分析等等编译过程,那么这个文本编辑器是否就称为某种语言的编辑器,能够实现编写和编译?本人觉得那应该是肯定的。
敬请大神们指摘。。。。完毕。