你的位置:首页 > Java教程

[Java教程]JAVA/GUI程序之记事本


  自上半年JAVA课程结束后,再也没有看过JAVA了,最近不是很忙,又简单的看了看,本博客纯属记录学习过程,请大神们别笑,其中错误是难免的,毕竟是新手写的博客。下面就进入我们的正题吧,复习GUI时,就想到WINDOWS的记事本,如果用GUI来仿写应该不难。实现向记事本这样的文本编辑器,第一步,当然是界面的问题,这对于GUI来说再简单不过了,所以我也不多说了,直接贴上代码即可,相信都能看懂。

创建菜单代码:

 1 //创建主菜单 2   public void createMenu() 3   { 4     //创建JMenuBar菜单条 5     mainMenuBar=new JMenuBar(); 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 void doNewFile() 2   { 3     int select,flag; 4     if (changed)//判断文件内容是否修改过 5     { 6       select=JOptionPane.showConfirmDialog(this,"文件修改后尚未存盘,要保存吗?"); 7       switch (select) 8       { 9       case JOptionPane.YES_OPTION:10         flag=doSave();11         break;12       case JOptionPane.NO_OPTION:13         flag=1;14         break;15       default:16         flag=0;17         break;18       }19     }20     else21     {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 void doOpenFile() 2   { 3     int select,flag; 4     File tmpfile=null; 5     ExampleFileFilter filter; 6     JFileChooser chooser;  7     FileInputStream fin; 8     byte  buf[]; 9     //判断文件内容是否修改过并询问是否存盘10     if (changed)11     {12       select=JOptionPane.showConfirmDialog(this,"文件已修改,是否要保存?");13       switch (select)14       {15       case JOptionPane.YES_OPTION:16         flag=doSave();17         break;18       case JOptionPane.NO_OPTION:19         flag=1;20         break;21       default:22         flag=0;23         break;24       }25     }26     else27     {28       flag = 1;29     }30     //当前文件处理完毕,准备打开一个文件31     if(flag==1)32     {33       changed = false;34       //设置文件类型过滤器35       filter = new ExampleFileFilter();36       filter.addExtension("txt");37       filter.setDescription("文本文件");38       //模拟记事本设置默认打开路径39       if (file!=null)40         chooser = new JFileChooser(file.getPath());41       else42         chooser = new JFileChooser();  43       chooser.setFileFilter(filter);44       select = chooser.showOpenDialog(this);45       if(select == JFileChooser.APPROVE_OPTION)46       {47         tmpfile=chooser.getSelectedFile();//使用文件流读入文件类容48         try49         {50           fin=new FileInputStream(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   int doSave() 3   { 4     FileOutputStream fout; 5     byte content[]; 6     int flag;      7     if (!haveName)//判断是否新建的文件 8     {  9       flag = doSaveAs();10     }11     else if(changed)//判断内容是否发生修改12     {13       try14       {15         fout=new FileOutputStream(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     else32     {33       flag =1;34     }35     return flag;36   }

  4.实现“另保存”功能:

    当使用者选择“另存为”菜单时,打开一个保存对话框,让使用者选择保存路径和文件名,如果文件名已存在,则弹出一个警告框,让使用者选择是否覆盖文件。否则以用户填写的文件名来保存文件并更改相关变量。

    为了实现这些功能,需要用到JFileChooser类和ExampleFileFilter类。而ExampleFileFilter类并不是JAVA标准库的类,所以必须将它引入的项目中,有关于相关的配置就不介绍了,网上有很多资料。同时,由于要处理用户的输入,因此需要大量的代码来提高容错率即程序的健壮性。具体代码如下:

 1 //用"另存为"对话框保存文件。保存成功返回1,否则返回0   2   int doSaveAs() 3   { 4     FileOutputStream fout; 5     byte content[]; 6     int flag=0; 7     File tmpfile=null; 8     ExampleFileFilter filter = new ExampleFileFilter(); 9     JFileChooser chooser; 10     filter.addExtension("txt");//设置保存文件对话框中的文件属性过滤器11     filter.setDescription("文本文件");12     if (file!=null)13       chooser = new JFileChooser(file.getPath());14     else15       chooser = new JFileChooser();  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         else29         {30           flag=0;31         }    32       }33       else34       {35         flag=1;36       }      37     }38     else39     {40       flag=0;41     }  42 43     if (flag==1)44     {//用户已经确定要以指定名称保存文件45       try46       {47         fout=new FileOutputStream(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     return flag;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   void doPrint() 3   { 4     try{  5       //构建打印属性集 6       PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet(); 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 = new HashDocAttributeSet();20         //建立打印文件格式21         Doc doc = new SimpleDoc(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 void processWindowEvent(WindowEvent e)  {    if (e.getID() == WindowEvent.WINDOW_CLOSING)        doExit();  }

//程序退出时的代码     void doExit()  {    int select;    if (!changed) //判断文件是否发生改变      System.exit(0);    else    {      select=JOptionPane.showConfirmDialog(this,"文件修改后尚未存盘,要保存吗?");      switch (select)      {      case JOptionPane.YES_OPTION:        select=doSave();        if (select==1)System.exit(0);        break;      case JOptionPane.NO_OPTION:        System.exit(0);        break;      case JOptionPane.CANCEL_OPTION:        break;      }    }  }

  7.“剪切”功能的实现:

    为了完成这一功能,应该为文本框添加两个监听器:键盘事件监听器KeyListener和鼠标事件监听器MouseListener。并且实现其中的keyPressed和mouseRealseed方法就可以了。这里我们采用继承相应的适配器类KeyAdapter和MouseAdapter即可。这部分相当简单,就不多说了。下面是具体代码:

//监听鼠标事件  class handleMouse extends MouseAdapter  {    public void mouseReleased(MouseEvent e)     {      chkText();    }    }  //监听键盘事件  class handleKey extends KeyAdapter  {    public void keyPressed(KeyEvent e)     {      chkText();    }   }  //根据用户选择文本的情况,修改菜单的状态  void chkText()  {    if(text.getSelectedText()==null)    {      cutItem.setEnabled(false);      copyItem.setEnabled(false);    }    else    {      cutItem.setEnabled(true);      copyItem.setEnabled(true);       }          }    //将用户选择的文本剪切到剪贴板  void doCut(){    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 implements ActionListener 6 { 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   int  start; 18   public findDialog(JFrame owner, JTextArea Jtext) 19   { 20     super(owner,false); 21     start=0; 22     text=Jtext; 23     panel1=new JPanel(); 24     panel1.setLayout(new FlowLayout()); 25     panel2=new JPanel(); 26     panel2.setLayout(new FlowLayout()); 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=new ButtonGroup(); 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(new FlowLayout()); 52     con.add(panel1); 53     con.add(panel2); 54     setTitle("查找"); 55     setSize(300,120); 56     setVisible(true); 57   } 58    59   public void actionPerformed(ActionEvent e) 60   { 61     if (e.getSource()==OKBtn) 62     { 63       find(e); 64     } 65     else 66     { 67       dispose(); 68     } 69   } 70   public void find(ActionEvent e) 71   { 72     int index; 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(int index) 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的记事本界面,但是,在此处涉及到布局的问题,我就采用了表格布局和流式布局。

代码如下:

//设置字体   void doChangeFont()  {    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 implements ActionListener,ListSelectionListener 7 { 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   private Container  con; 20   private JScrollPane nameSPane,styleSPane,sizeSPane; 21   private JPanel   panel[]; 22   private JLabel   nameLbl,styleLbl,sizeLbl; 23   private JTextField nameText,styleText,sizeText; 24   private JList    nameList,styleList,sizeList; 25   private JButton   OKBtn,cancleBtn; 26  27   public fontDialog() 28   { 29     this(null); 30   } 31    32   public fontDialog(JFrame owner) 33   { 34     super(owner,true); 35     parent=owner; 36     setTitle("字体"); 37     con=getContentPane(); 38     BoxLayout box=new BoxLayout(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]=new JPanel(); 44       panel[i].setLayout(new GridLayout(1,3)); 45     } 46     panel[3]=new JPanel(); 47     panel[3].setLayout(new FlowLayout()); 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=new JList(availableFonts); 72     nameList.addListSelectionListener(this); 73     nameSPane=new JScrollPane(nameList); 74     styleList=new JList(style); 75     styleList.addListSelectionListener(this); 76     styleSPane=new JScrollPane(styleList); 77     sizeList=new JList(size); 78     sizeList.addListSelectionListener(this); 79     sizeSPane=new JScrollPane(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 int showFontDialog() 96   { 97     setSize(300,300); 98     int x,y; 99     if (parent!=null)100     {101       x=parent.getX()+30;102       y=parent.getY()+30;103     }104     else105     {106       x=150;107       y=100;108     }109     setLocation(new Point(x,y));110     setVisible(true);111     return userSelect; 112   }113 114   public Font getFont()115   {116     return userFont;117   }118 119   public void actionPerformed(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=new Font(nameText.getText(),styleIndex,fontSize);134       userSelect=OK;135       setVisible(false);136     }137     else138     {139       userSelect=Cancle;140       setVisible(false);141     }142   }143   144   public void valueChanged(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 void createPopupMenu()  {    popMenu=new JPopupMenu();    popMenu.add("撤消");    popMenu.addSeparator();    popMenu.add("剪切");    popMenu.add("复制");    popMenu.add("粘贴");    popMenu.addSeparator();    popMenu.add("全选");  }

  然后用setComponentPopupMenu()为文本去加上这个菜单即可。

  至于复制、粘贴、全选、替换、获取时间/日期和自动换行等功能比较简单,就不累述了。

  本博客是参考相关的java资料,我们在大学学了很多种语言,要尝试着用不同的语言来实现,虽然思路是一样的,但是实现的过程中还是有相当部分不同的。当然,本例只是给出了纯文本编辑器,不能进行其他方面操作。其实本人也在想如果我们将编译原理的知识加进来,实现某种简单语言(如:PL/0语言)的词法分析、语法分析、语义分析等等编译过程,那么这个文本编辑器是否就称为某种语言的编辑器,能够实现编写和编译?本人觉得那应该是肯定的。

  敬请大神们指摘。。。。完毕。