自上半年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語言)的詞法分析、語法分析、語義分析等等編譯過程,那么這個文本編輯器是否就稱為某種語言的編輯器,能夠實現編寫和編譯?本人覺得那應該是肯定的。
敬請大神們指摘。。。。完畢。