
?記事本有很多功能,本小節(jié)將講解其中較為重要的功能的實(shí)現(xiàn)過(guò)程。
記事本界面上最多的就是菜單和菜單項(xiàng)。如果在窗體上添加菜單,先要添加一個(gè)菜單欄。在Swing體系中,用JMenuBar類表示菜單欄,創(chuàng)建菜單欄的語(yǔ)句如下:?
(資料圖片僅供參考)
JMenuBar mainMenuBar=new JMenuBar();?
創(chuàng)建菜單欄、給菜單欄添加菜單、給菜單添加菜單項(xiàng)以及給菜單項(xiàng)添加監(jiān)聽(tīng)器的操作全部集中在createMenu()方法中實(shí)現(xiàn),而createMenu()方法又在專門(mén)初始化組件的init()方法中被調(diào)用,以下是createMenu()方法的實(shí)現(xiàn)過(guò)程。?
public void createMenu(){ //創(chuàng)建JMenuBar mainMenuBar=new JMenuBar(); //創(chuàng)建四個(gè)JMenu fileMenu=new JMenu("文件"); editMenu=new JMenu("編輯"); formatMenu=new JMenu("格式"); helpMenu=new JMenu("幫助"); //創(chuàng)建JMenuItem并添加到對(duì)應(yīng)的JMenu中 mainMenuBar.add(fileMenu); newItem=new JMenuItem("新建"); openItem=new JMenuItem("打開(kāi).."); saveItem=new JMenuItem("保存.."); saveasItem=new JMenuItem("另存為.."); pageItem=new JMenuItem("頁(yè)面設(shè)置.."); 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("復(fù)制"); pasteItem=new JMenuItem("粘貼"); findItem=new JMenuItem("查找.."); replaceItem=new JMenuItem("替換.."); selectallItem=new JMenuItem("全選"); dateItem=new JMenuItem("時(shí)間/日期"); 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("自動(dòng)換行"); fontItem=new JMenuItem("設(shè)置字體.."); formatMenu.add(wrapItem); formatMenu.add(fontItem); mainMenuBar.add(helpMenu); helpItem=new JMenuItem("幫助主題"); aboutItem=new JMenuItem("關(guān)于.."); helpMenu.add(helpItem); helpMenu.add(aboutItem); //給菜單項(xiàng)添加監(jiān)聽(tīng)器 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);}
當(dāng)用戶單擊“保存”菜單項(xiàng)時(shí),程序必須完成以下操作:?
判斷文件是否為新文件,如果是新文件調(diào)用doSaveAs()方法實(shí)現(xiàn)保存操作。?如果不是新文件,查看上次保存之后是否有過(guò)修改操作,如果有修改操作直接以原文件名保存,否則調(diào)用doSaveAs()方法進(jìn)行保存。?如果沒(méi)有任何修改,則不需要做任何操作。?與保存相關(guān)的操作基本都由doSaveAs()方法完成的,doSaveAs()方法的實(shí)現(xiàn)過(guò)程如下:?
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,"文件已經(jīng)存在,是否覆蓋?", "警告", JOptionPane.YES_NO_OPTION)==JOptionPane.YES_OPTION){ flag=1; }else{ flag=0; } }else{ flag=1; } }else{ flag=0; } if (flag==1){//用戶已經(jīng)確定要以指定名稱保存文件 try{ fout=new FileOutputStream(tmpfile); content=text.getText().getBytes(); fout.write(content); fout.close(); flag = 1; }catch(FileNotFoundException e){ JOptionPane.showMessageDialog(this,"指定的文件名稱或?qū)傩杂袉?wèn)題!"); flag = 0; }catch(IOException e){ JOptionPane.showMessageDialog(this,"無(wú)法寫(xiě)文件,請(qǐng)檢查文件是否被鎖定"); flag = 0; } } if (flag==1){//文件保存成功,修改相關(guān)變量 changed=false; haveName=true; file=tmpfile; this.setTitle("記事本 -- "+file.getName()); } return flag;}
當(dāng)用戶單擊“打開(kāi)”菜單項(xiàng)時(shí),程序應(yīng)完成以下操作:?
判斷當(dāng)前文件是否被修改過(guò),如果修改過(guò)則詢問(wèn)用戶是否要保存當(dāng)前文件。?如果用戶選擇“取消”則關(guān)閉對(duì)話框,否則彈出文件選擇對(duì)話框由用戶選擇要打開(kāi)的文件。?讀入用戶選擇的文件內(nèi)容,并把這些內(nèi)容顯示到窗體的文本區(qū)text中。?打開(kāi)操作主要調(diào)用doOpen()方法完成,其實(shí)現(xiàn)過(guò)程如下:?
//打開(kāi)一個(gè)已經(jīng)存在的文件void doOpen(){ int select,flag; File tmpfile=null; ExampleFileFilter filter; JFileChooser chooser; FileInputStream fin; byte buf[]; if (changed){ select=JOptionPane.showConfirmDialog(this,"文件修改后尚未存盤(pán),要保存嗎?"); 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,"指定的文件名稱或?qū)傩杂袉?wèn)題!"); }catch(IOException e){ JOptionPane.showMessageDialog(this,"無(wú)法讀文件,請(qǐng)檢查文件是否被鎖定"); } } }}
一般情況下,用戶如果沒(méi)有選擇文本,那么剪切和復(fù)制菜單項(xiàng)應(yīng)處于不可用狀態(tài),而一旦用戶選擇了一段文本,則這兩個(gè)菜單項(xiàng)就應(yīng)該立刻變成可用狀態(tài)。?
為實(shí)現(xiàn)這種效果,應(yīng)該為文本區(qū)添加兩個(gè)監(jiān)聽(tīng)器,分別是鍵盤(pán)監(jiān)聽(tīng)器和鼠標(biāo)監(jiān)聽(tīng)器。在本案例的程序代碼中以適配器類的子類作為監(jiān)聽(tīng)器的實(shí)現(xiàn)類,并且這兩個(gè)監(jiān)聽(tīng)器類被定義為內(nèi)部類。這兩個(gè)監(jiān)聽(tīng)器主要監(jiān)聽(tīng)文檔是否發(fā)生了修改,其實(shí)現(xiàn)過(guò)程如下:
//鍵盤(pán)監(jiān)聽(tīng)器類class HandleKey extends KeyAdapter { public void keyPressed(KeyEvent e) { chkText(); }}//鼠標(biāo)監(jiān)聽(tīng)器類class HandleMouse extends MouseAdapter { public void mouseReleased(MouseEvent e) { chkText(); }}//根據(jù)用戶選擇文本的情況,修改菜單的狀態(tài)void chkText() { if (text.getSelectedText() == null) { cutItem.setEnabled(false); copyItem.setEnabled(false); } else { cutItem.setEnabled(true); copyItem.setEnabled(true); }}
全選功能由doSelectAll()方法實(shí)現(xiàn),其代碼如下:?
//全選?void doSelectAll() {? text.selectAll();?}?
有了前面的準(zhǔn)備工作,復(fù)制文本變得很簡(jiǎn)單,只需要調(diào)用doCopy()方法就能實(shí)現(xiàn),其代碼如下:?
//將用戶選擇的文本復(fù)制到剪貼板?void doCopy() {? text.copy();?}?
同樣的,實(shí)現(xiàn)剪切操作也很簡(jiǎn)單,只需要調(diào)用doCut()方法就能實(shí)現(xiàn),其代碼如下:?
//將用戶選擇的文本復(fù)制到剪貼板?void doCut() {? text.cut();?}?
粘貼功能由doPaste()方法實(shí)現(xiàn),其代碼如下:?
//將剪貼板中的內(nèi)容復(fù)制到文本區(qū)?void doPaste() {? text.paste();?}?
Java的打印API主要存在于java.awt.print包下,而JDK1.4新增的與打印相關(guān)的類則在javax.print包以及它的子包javax.print和javax.print.event和javax.print.attribute中。?
要實(shí)現(xiàn)打印操作,需要完成以下幾個(gè)步驟:?
定位一臺(tái)打印機(jī)?指定打印內(nèi)容的格式?設(shè)置打印屬性?設(shè)置內(nèi)容?打印?其中第三步一般通過(guò)一個(gè)對(duì)話框完成,從JDK1.4開(kāi)始ServiceUI打印對(duì)話框,其界面如圖22-4所示。?
圖22-4打印屬性對(duì)話框?
打印操作由doPrint()方法完成,其實(shí)現(xiàn)過(guò)程如下:?
//調(diào)用打印對(duì)話框,給用戶打印文檔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); //進(jìn)行文件的打印 } } catch (Exception e) { JOptionPane.showMessageDialog(this, "打印任務(wù)無(wú)法完成"); }}
查找功能對(duì)話框由FindDialog類實(shí)現(xiàn),它是對(duì)話框類JDialog的子類。由于查找時(shí)是在查找對(duì)話框中設(shè)置關(guān)鍵字并且在NoteBookFrame類表示文本區(qū)的text組件中完成。從界面上來(lái)看,text是一個(gè)文本區(qū),而從代碼的角度來(lái)看text是NoteBookFrame的屬性。為了訪問(wèn)這個(gè)屬性,可以通過(guò)構(gòu)造方法的參數(shù)把這個(gè)屬性傳遞給FindDialog類對(duì)象,這樣當(dāng)找到關(guān)鍵字時(shí)就能操作這個(gè)text組件,因此FindDialog類的構(gòu)造方法應(yīng)設(shè)計(jì)為:?
public FindDialog(JFrame owner, JTextArea text) {? super(owner,false);? init(text);?}?
如果能找到關(guān)鍵字,則調(diào)用text的select()方法選中關(guān)鍵字,如果找不到關(guān)鍵字,則彈出一個(gè)對(duì)話框提示用戶。限于篇幅,查找對(duì)話框的實(shí)現(xiàn)過(guò)程暫不給出,而在22.3小節(jié)的項(xiàng)目完整代碼中一并給出。?
設(shè)置字體對(duì)話框由FontDialog類表示,F(xiàn)ontDialog也是JDialog的子類。設(shè)置字體對(duì)話框的界面如圖22-2所示,從圖中可以看出:對(duì)話框中有三個(gè)列表框,用戶可以在這三個(gè)列表框中分別選擇字體、字形和大小,當(dāng)單擊“確定”按鈕后就能修改記事本中的字體。?
在程序中,打開(kāi)設(shè)置字體對(duì)話框的方法是doChangeFont(),其實(shí)現(xiàn)過(guò)程如下:?
//設(shè)置字體?void doChangeFont() {? if (myFontDialog == null) {? myFontDialog = new FontDialog(this);? }? if (myFontDialog.showFontDialog() == FontDialog.OK) {? text.setFont(myFontDialog.getFont());//獲得對(duì)話框返回的字體并以它作為記事本字體? }?}?
當(dāng)用戶單擊“退出”菜單項(xiàng)時(shí),程序應(yīng)該完成以下操作。?
如果文件已經(jīng)被保存,則直接退出。?如果文件沒(méi)有被保存,則彈出對(duì)話框詢問(wèn)用戶是否要保存文件。?如果用戶選擇不保存,則直接退出。?如果用戶選擇取消,則關(guān)閉對(duì)話框。?為了完成以上操作,需要定義兩個(gè)關(guān)鍵的boolean型變量:?
changed:用來(lái)標(biāo)識(shí)文件是否已經(jīng)被修改。?haveName:用來(lái)標(biāo)識(shí)文件是否有名字,實(shí)際上也是標(biāo)識(shí)文件是不是新文件。?退出操作由doExit()方法完成,其實(shí)現(xiàn)過(guò)程如下:?
//退出記事本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; } }}
本文字版教程還配有更詳細(xì)的視頻講解,小伙伴們可以??點(diǎn)擊這里??觀看。
標(biāo)簽: 設(shè)置字體 關(guān)閉對(duì)話框 打印對(duì)話框