记事本有很多功能,本小节将讲解其中较为重要的功能的实现过程。
记事本界面上最多的就是菜单和菜单项。如果在窗体上添加菜单,先要添加一个菜单栏。在Swing体系中,用JMenuBar类表示菜单栏,创建菜单栏的语句如下:
JMenuBar mainMenuBar=new JMenuBar();
创建菜单栏、给菜单栏添加菜单、给菜单添加菜单项以及给菜单项添加监听器的操作全部集中在createMenu()方法中实现,而createMenu()方法又在专门初始化组件的init()方法中被调用,以下是createMenu()方法的实现过程。
- public void createMenu(){
- //创建JMenuBar
- mainMenuBar=new JMenuBar();
- //创建四个JMenu
- fileMenu=new JMenu("文件");
- editMenu=new JMenu("编辑");
- formatMenu=new JMenu("格式");
- helpMenu=new JMenu("帮助");
- //创建JMenuItem并添加到对应的JMenu中
- mainMenuBar.add(fileMenu);
- newItem=new JMenuItem("新建");
- openItem=new JMenuItem("打开..");
- saveItem=new JMenuItem("保存..");
- saveasItem=new JMenuItem("另存为..");
- pageItem=new JMenuItem("页面设置..");
- printItem=new JMenuItem("打印..");
- exitItem=new JMenuItem("退出");
- fileMenu.add(newItem);
- fileMenu.add(openItem);
- fileMenu.add(saveItem);
- fileMenu.add(saveasItem);
- fileMenu.addSeparator();
- fileMenu.add(pageItem);
- fileMenu.add(printItem);
- fileMenu.addSeparator();
- fileMenu.add(exitItem);
- mainMenuBar.add(editMenu);
- undoItem=new JMenuItem("撤消");
- cutItem=new JMenuItem("剪切");
- copyItem=new JMenuItem("复制");
- pasteItem=new JMenuItem("粘贴");
- findItem=new JMenuItem("查找..");
- replaceItem=new JMenuItem("替换..");
- selectallItem=new JMenuItem("全选");
- dateItem=new JMenuItem("时间/日期");
- editMenu.add(undoItem);
- editMenu.addSeparator();
- editMenu.add(cutItem);
- editMenu.add(copyItem);
- editMenu.add(pasteItem);
- editMenu.addSeparator();
- editMenu.add(findItem);
- editMenu.add(replaceItem);
- editMenu.addSeparator();
- editMenu.add(selectallItem);
- editMenu.add(dateItem);
- mainMenuBar.add(formatMenu);
- wrapItem=new JCheckBoxMenuItem("自动换行");
- fontItem=new JMenuItem("设置字体..");
- formatMenu.add(wrapItem);
- formatMenu.add(fontItem);
- mainMenuBar.add(helpMenu);
- helpItem=new JMenuItem("帮助主题");
- aboutItem=new JMenuItem("关于..");
- helpMenu.add(helpItem);
- helpMenu.add(aboutItem);
- //给菜单项添加监听器
- exitItem.addActionListener(listener);
- saveItem.addActionListener(listener);
- saveasItem.addActionListener(listener);
- newItem.addActionListener(listener);
- printItem.addActionListener(listener);
- openItem.addActionListener(listener);
- cutItem.addActionListener(listener);
- copyItem.addActionListener(listener);
- pasteItem.addActionListener(listener);
- selectallItem.addActionListener(listener);
- dateItem.addActionListener(listener);
- wrapItem.addActionListener(listener);
- findItem.addActionListener(listener);
- fontItem.addActionListener(listener);
- }
当用户单击“保存”菜单项时,程序必须完成以下操作:
与保存相关的操作基本都由doSaveAs()方法完成的,doSaveAs()方法的实现过程如下:
- int doSaveAs(){
- FileOutputStream fout;
- byte content[];
- int flag=0;
- File tmpfile=null;
- ExampleFileFilter filter = new ExampleFileFilter();
- JFileChooser chooser;
- filter.addExtension("txt");
- filter.setDescription("文本文件");
- if (file!=null){
- chooser = new JFileChooser(file.getPath());
- }
- else{
- chooser = new JFileChooser();
- }
- chooser.setFileFilter(filter);
- flag = chooser.showSaveDialog(this);
- if(flag == JFileChooser.APPROVE_OPTION) {
- tmpfile=chooser.getSelectedFile();
- if (tmpfile.exists()){
- if (JOptionPane.showConfirmDialog(this,"文件已经存在,是否覆盖?", "警告",
- JOptionPane.YES_NO_OPTION)==JOptionPane.YES_OPTION){
- flag=1;
- }else{
- flag=0;
- }
- }else{
- flag=1;
- }
- }else{
- flag=0;
- }
-
-
- if (flag==1){//用户已经确定要以指定名称保存文件
- try{
- fout=new FileOutputStream(tmpfile);
- content=text.getText().getBytes();
- fout.write(content);
- fout.close();
- flag = 1;
- }catch(FileNotFoundException e){
- JOptionPane.showMessageDialog(this,"指定的文件名称或属性有问题!");
- flag = 0;
- }catch(IOException e){
- JOptionPane.showMessageDialog(this,"无法写文件,请检查文件是否被锁定");
- flag = 0;
- }
- }
-
- if (flag==1){//文件保存成功,修改相关变量
- changed=false;
- haveName=true;
- file=tmpfile;
- this.setTitle("记事本 -- "+file.getName());
- }
- return flag;
- }
当用户单击“打开”菜单项时,程序应完成以下操作:
打开操作主要调用doOpen()方法完成,其实现过程如下:
- //打开一个已经存在的文件
- void doOpen(){
- int select,flag;
- File tmpfile=null;
- ExampleFileFilter filter;
- JFileChooser chooser;
- FileInputStream fin;
- byte buf[];
- if (changed){
- select=JOptionPane.showConfirmDialog(this,"文件修改后尚未存盘,要保存吗?");
- switch (select){
- case JOptionPane.YES_OPTION:
- flag=doSave();
- break;
- case JOptionPane.NO_OPTION:
- flag=1;
- break;
- default:
- flag=0;
- break;
- }
- }else{
- flag = 1;
- }
- if(flag==1){
- changed = false;
- filter = new ExampleFileFilter();
- filter.addExtension("txt");
- filter.setDescription("文本文件");
- if (file!=null){
- chooser = new JFileChooser(file.getPath());
- }
- else{
- chooser = new JFileChooser();
- }
- chooser.setFileFilter(filter);
- select = chooser.showOpenDialog(this);
- if(select == JFileChooser.APPROVE_OPTION) {
- tmpfile=chooser.getSelectedFile();
- try{
- fin=new FileInputStream(tmpfile);
- buf=new byte[(int)tmpfile.length()];
- fin.read(buf);
- fin.close();
- text.setText(new String(buf));
- changed=false;
- haveName=true;
- file=tmpfile;
- setTitle("记事本 -- "+file.getName());
- }catch(FileNotFoundException e){
- JOptionPane.showMessageDialog(this,"指定的文件名称或属性有问题!");
- }catch(IOException e){
- JOptionPane.showMessageDialog(this,"无法读文件,请检查文件是否被锁定");
- }
- }
- }
- }
一般情况下,用户如果没有选择文本,那么剪切和复制菜单项应处于不可用状态,而一旦用户选择了一段文本,则这两个菜单项就应该立刻变成可用状态。
为实现这种效果,应该为文本区添加两个监听器,分别是键盘监听器和鼠标监听器。在本案例的程序代码中以适配器类的子类作为监听器的实现类,并且这两个监听器类被定义为内部类。这两个监听器主要监听文档是否发生了修改,其实现过程如下:
- //键盘监听器类
- class HandleKey extends KeyAdapter {
- public void keyPressed(KeyEvent e) {
- chkText();
- }
- }
-
- //鼠标监听器类
- class HandleMouse extends MouseAdapter {
- public void mouseReleased(MouseEvent e) {
- chkText();
- }
- }
-
- //根据用户选择文本的情况,修改菜单的状态
- void chkText() {
- if (text.getSelectedText() == null) {
- cutItem.setEnabled(false);
- copyItem.setEnabled(false);
- } else {
- cutItem.setEnabled(true);
- copyItem.setEnabled(true);
- }
- }
全选功能由doSelectAll()方法实现,其代码如下:
- //全选
- void doSelectAll() {
- text.selectAll();
- }
有了前面的准备工作,复制文本变得很简单,只需要调用doCopy()方法就能实现,其代码如下:
- //将用户选择的文本复制到剪贴板
- void doCopy() {
- text.copy();
- }
同样的,实现剪切操作也很简单,只需要调用doCut()方法就能实现,其代码如下:
- //将用户选择的文本复制到剪贴板
- void doCut() {
- text.cut();
- }
粘贴功能由doPaste()方法实现,其代码如下:
- //将剪贴板中的内容复制到文本区
- void doPaste() {
- text.paste();
- }
Java的打印API主要存在于java.awt.print包下,而JDK1.4新增的与打印相关的类则在javax.print包以及它的子包javax.print和javax.print.event和javax.print.attribute中。
要实现打印操作,需要完成以下几个步骤:
其中第三步一般通过一个对话框完成,从JDK1.4开始ServiceUI打印对话框,其界面如图22-4所示。

图22-4打印属性对话框
打印操作由doPrint()方法完成,其实现过程如下:
- //调用打印对话框,给用户打印文档
- void doPrint() {
- try {
- PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
- DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
- PrintService printService[] = PrintServiceLookup.lookupPrintServices(flavor, pras);
- PrintService defaultService = PrintServiceLookup.lookupDefaultPrintService();
- PrintService service = null;
- service=ServiceUI.printDialog(null, 100, 100, printService, defaultService, flavor, pras);
- if (service != null) {
- DocPrintJob job = service.createPrintJob();
- DocAttributeSet das = new HashDocAttributeSet();
- Doc doc = new SimpleDoc(text.getText().getBytes(), flavor, das);
- job.print(doc, pras); //进行文件的打印
- }
- } catch (Exception e) {
- JOptionPane.showMessageDialog(this, "打印任务无法完成");
- }
- }
查找功能对话框由FindDialog类实现,它是对话框类JDialog的子类。由于查找时是在查找对话框中设置关键字并且在NoteBookFrame类表示文本区的text组件中完成。从界面上来看,text是一个文本区,而从代码的角度来看text是NoteBookFrame的属性。为了访问这个属性,可以通过构造方法的参数把这个属性传递给FindDialog类对象,这样当找到关键字时就能操作这个text组件,因此FindDialog类的构造方法应设计为:
- public FindDialog(JFrame owner, JTextArea text) {
- super(owner,false);
- init(text);
- }
如果能找到关键字,则调用text的select()方法选中关键字,如果找不到关键字,则弹出一个对话框提示用户。限于篇幅,查找对话框的实现过程暂不给出,而在22.3小节的项目完整代码中一并给出。
设置字体对话框由FontDialog类表示,FontDialog也是JDialog的子类。设置字体对话框的界面如图22-2所示,从图中可以看出:对话框中有三个列表框,用户可以在这三个列表框中分别选择字体、字形和大小,当单击“确定”按钮后就能修改记事本中的字体。
在程序中,打开设置字体对话框的方法是doChangeFont(),其实现过程如下:
- //设置字体
- void doChangeFont() {
- if (myFontDialog == null) {
- myFontDialog = new FontDialog(this);
- }
- if (myFontDialog.showFontDialog() == FontDialog.OK) {
- text.setFont(myFontDialog.getFont());//获得对话框返回的字体并以它作为记事本字体
- }
- }
当用户单击“退出”菜单项时,程序应该完成以下操作。
为了完成以上操作,需要定义两个关键的boolean型变量:
退出操作由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;
- }
- }
- }