一、概述
文本編輯器是一種最常用的應用程序,下面我們利用Jbuilder 9集成開發環境,用java語言實現一個簡單的文本編輯器。該文本編輯器具有讀出、寫入、編輯文本文件,可以設定文字顏色、字形和編輯區域背景顏色等基本功能。
我們首先通過Jbuilder 9項目向導和應用向導創建項目,然后應用可視化設計工具,修改UI設計,連接事件,編輯源碼以及常用控件和任務諸如菜單項、工具條、文本區域和系統事件等常用控件和任務的處理。涉及到具體技術有:
用JFileChooser 對話框讓用戶選擇文本文件。
用JtextArea讀、寫和處理文本文件中的文字。
設置前景色和背景色。
用dbSwing FontChooser對話框設置字型。
在狀態欄和窗口標題欄顯示信息。
手工添加處理UI事件的代碼 。
通過將代碼放在一個可被菜單項和按鈕兩個事件處理器調用的新的"幫助"方法中, 使得菜單項和按鈕執行相同的代碼。
給JtextArea控件增加一個右擊菜單。
保持對文件的位置以及文件是否活動過的跟蹤,展示對文件|新建, 文件|打開, 文件|保存, 文件|另存為,編輯和退出等邏輯的處理。
將"Text Editor" 應用程序展開為JAR 文件。
二、開發文本編輯器java源程序說明
文本編輯器程序包含三個java 源程序即TextEditFrame.java、TextEditclass.java 和TextEditFrame_AboutBox.java 程序,下面將分別介紹如下:
1、TextEditFrame.java的源程序代碼(節選部分):
package texteditor; //TextEditFrame.java import java.awt.*;//導入類 import java.awt.event.*; import javax.swing.*; import com.borland.dbswing.*; import java.io.*; import javax.swing.text.*; import javax.swing.event.*; public class TextEditFrame extends JFrame { IntlSwingSupport intlSwingSupport1 = new IntlSwingSupport(); //Swing 控件互聯網化:即本地化應用程序,需要添加一行代碼以便Swing 控件JfileChooser //和JcolorChooser出現在程序運行的語言中 JPanel contentPane; //設置內容窗(contentPane)的JPanel控件 JMenuBar menuBar1 = new JMenuBar();//創建菜單條并加入到框架窗體中 JMenu menuFile = new JMenu();//創建File菜單和相應的菜單項 JMenuItem menuFileExit = new JMenuItem(); JMenu menuHelp = new JMenu();//創建Help菜單和相應的菜單項 JMenuItem menuHelpAbout = new JMenuItem(); JToolBar toolBar = new JToolBar();//創建工具條組件 JButton jButton1 = new JButton();//創建按鈕組件 JButton jButton2 = new JButton(); JButton jButton3 = new JButton(); ImageIcon image1;//定義圖標 ImageIcon image2; ImageIcon image3; JLabel statusBar = new JLabel();//創建標簽組件 BorderLayout borderLayout1 = new BorderLayout();//創建BorderLayout 布局器 JScrollPane jScrollPane1 = new JScrollPane();//創建滾動窗控件 JTextArea jTextArea1 = new JTextArea();//創建多行文本域組件 JMenuItem jMenuItem1 = new JMenuItem();//創建菜單項 JMenuItem jMenuItem2 = new JMenuItem(); JMenuItem jMenuItem3 = new JMenuItem(); JMenuItem jMenuItem4 = new JMenuItem(); FontChooser fontChooser1 = new FontChooser();//創建字型選擇對話框 JMenu jMenu1 = new JMenu(); JMenuItem jMenuItem5 = new JMenuItem(); JMenuItem jMenuItem6 = new JMenuItem(); JMenuItem jMenuItem7 = new JMenuItem(); JFileChooser jFileChooser1 = new JFileChooser();//創建文本選擇對話框 String currFileName = null; // Full path with filename. null means new/untitled. boolean dirty = false; Document document1; //文本 DBTextDataBinder dBTextDataBinder1 = new DBTextDataBinder(); // True means modified text. //構造架框 public TextEditFrame() { enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { jbInit(); updateCaption(); } catch(Exception e) { e.printStackTrace(); } } //組件初始化 private void jbInit() throws Exception { //三個工具欄按鈕圖標 image1 = new ImageIcon(TextEditFrame.class.getResource("openFile.gif")); image2 = new ImageIcon(TextEditFrame.class.getResource("closeFile.gif")); image3 = new ImageIcon(TextEditFrame.class.getResource("help.gif")); contentPane = (JPanel) this.getContentPane();//內容創格 document1 = jTextArea1.getDocument();//多行文本域文檔 contentPane.setLayout(borderLayout1);//borderLayout布局器 this.setSize(new Dimension(400, 300));//窗口大小 this.setTitle("Text Editor");//窗口標題 statusBar.setText(" "); menuFile.setText("File"); menuFileExit.setText("Exit"); menuFileExit.addActionListener(new TextEditFrame_menuFileExit_ActionAdapter (this)); //添加事件監聽器 menuHelp.setText("Help"); menuHelpAbout.setText("About"); menuHelpAbout.addActionListener(new TextEditFrame_menuHelpAbout_ActionAdapter (this)); jButton1.setIcon(image1);//設置三個工具欄按鈕圖標,添加事件監聽器 jButton1.addActionListener(new TextEditFrame_jButton1_actionAdapter(this)); jButton1.setToolTipText("Open File"); jButton2.setIcon(image2); jButton2.addActionListener(new TextEditFrame_jButton2_actionAdapter(this)); jButton2.setToolTipText("Close File"); jButton3.setIcon(image3); jButton3.addActionListener(new TextEditFrame_jButton3_actionAdapter(this)); jButton3.setToolTipText("About"); jTextArea1.setLineWrap(true); jTextArea1.setWrapStyleWord(true); jTextArea1.setBackground(Color.white); jMenuItem1.setText("New");//設置菜單,添加事件監聽器 jMenuItem1.addActionListener(new TextEditFrame_jMenuItem1_actionAdapter(this)); jMenuItem2.setText("Open"); jMenuItem2.addActionListener(new TextEditFrame_jMenuItem2_actionAdapter(this)); jMenuItem3.setText("Save"); jMenuItem3.addActionListener(new TextEditFrame_jMenuItem3_actionAdapter(this)); jMenuItem4.setText("Save As"); jMenuItem4.addActionListener(new TextEditFrame_jMenuItem4_actionAdapter(this)); fontChooser1.setFrame(this); fontChooser1.setTitle("Font"); jMenu1.setText("Edit"); jMenuItem5.setText("Font"); jMenuItem5.addActionListener(new TextEditFrame_jMenuItem5_actionAdapter(this)); jMenuItem6.setText("Foreground Color"); jMenuItem6.addActionListener(new TextEditFrame_jMenuItem6_actionAdapter(this)); jMenuItem7.setText("Background Color"); jMenuItem7.addActionListener(new TextEditFrame_jMenuItem7_actionAdapter(this)); document1.addDocumentListener(new TextEditFrame_document1_documentAdapter(this)); dBTextDataBinder1.setJTextComponent(jTextArea1); //Turn off right-click file Open... menu item. dBTextDataBinder1.setEnableFileLoading(false); //Turn off right-click file Save... menu item. dBTextDataBinder1.setEnableFileSaving(false); toolBar.add(jButton1);//工具組件添加按鈕 toolBar.add(jButton2); toolBar.add(jButton3); menuFile.add(jMenuItem1);//菜單組件添加菜單項 menuFile.add(jMenuItem2); menuFile.add(jMenuItem3); menuFile.add(jMenuItem4); menuFile.addSeparator();//采單組件添加分隔線 menuFile.add(menuFileExit); menuHelp.add(menuHelpAbout); menuBar1.add(menuFile); menuBar1.add(jMenu1); menuBar1.add(menuHelp); this.setJMenuBar(menuBar1); contentPane.add(toolBar, BorderLayout.NORTH); //內容窗設置borderLayout布局器 contentPane.add(statusBar, BorderLayout.SOUTH); contentPane.add(jScrollPane1, BorderLayout.CENTER); jScrollPane1.getViewport().add(jTextArea1, null); jMenu1.add(jMenuItem5); jMenu1.add(jMenuItem6); jMenu1.add(jMenuItem7); } // Display the About box. void helpAbout() { TextEditFrame_AboutBox dlg = new TextEditFrame_AboutBox(this); Dimension dlgSize = dlg.getPreferredSize(); Dimension frmSize = getSize(); Point loc = getLocation(); dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x, (frmSize.height - dlgSize.height) / 2 + loc.y); dlg.setModal(true); dlg.show(); } ......... .........
TextEditFrame.java 是實現文本編輯器的主要程序,它有下面6點編程技巧說明:
1) 制作一個完全充滿用戶界面頂部菜單欄和底部狀態欄之間區域的文本區
主用戶界面容器的布局管理器需要采用邊界布局(Borderlayout)。在主容器中,含有一個叫做內容窗(contentPane)的JPanel 控件,被改變成邊界布局,需要做的只是在內容窗添加一個文本區控件。為此,先在內容窗添加一個滾動窗,再在滾動窗內放上文本區控件(jTextArea)。滾動窗提供一個帶滾動棒(JScollPane)的文本區。
一個邊界布局的容器被分成五個區域:北、南、東、西、中。每個區域只能有一個控件,所以最多可有五個控件(注:含有多個控件的面板被認為是一個控件)。放進中心區域的控件完全占滿該容器控件,不被含有控件的任何其他區域所占據。例如,在本例中,工具欄占據北區(頂),狀態欄占據南區(低步),由于東西兩個區域沒有安排控件,這樣滾動窗控件占據中心區域并擴展到容器的左(西)右(東)的邊緣。
2) 創建菜單File (包含New、Open、Save、Save as 和Exit菜單項),菜單Edit{包含Font(字體)、Foreground(前景色)和Background(背景色)菜單項} 和菜單Help (包含About幫助說明)
①菜單Edit的Font(字體)、Foreground(前景色)和Background(背景色)菜單項:
添加字型選擇對話框
給菜單掛上事件,從 Edit|Font 菜單項開始,該菜單將引出一個FontChooser (字型選擇)對話框。 給FontChooser附加一個菜單項事件(源程序)如下:
void jMenuItem5_actionPerformed(ActionEvent e) { // Handle the "Edit Font" menu item // Pick up the existing font from the text area // and put it into the FontChooser before showing // the FontChooser, so that we are editing the // existing / previous font.
fontChooser1.setSelectedFont(jTextArea1.getFont());
// Obtain the new Font from the FontChooser. // First test the return value of showDialog() to // see if the user pressed OK. if (fontChooser1.showDialog()) { // Set the font of jTextArea1 to the font // the user selected before pressing the OK button jTextArea1.setFont(fontChooser1.getSelectedFont()); } //repaints menu after item is selected this.repaint(); //Repaints text properly if some text is highlighted when font is changed. jTextArea1.repaint(); }
給JcolorChooser(顏色選擇)附加一個菜單項事件
創建Edit|Foreground and Edit|Background兩個菜單事件,并將它們與Swing中的JcolorChooser對話控件連接起來。
void jMenuItem6_actionPerformed(ActionEvent e) { // Handle the "Foreground Color" menu item Color color = JColorChooser.showDialog(this,"Foreground Color",jTextArea1.getForeground()); if (color != null) { jTextArea1.setForeground(color); } //repaints menu after item is selected this.repaint(); } void jMenuItem7_actionPerformed(ActionEvent e) { // Handle the "Background Color" menu item Color color = JColorChooser.showDialog(this,"Background Color",jTextArea1.getBackground()); if (color != null) { jTextArea1.setBackground(color); } //repaints menu after item is selected this.repaint(); }
②菜單File 的New、Open、Save、Save as 和Exit菜單項:
添加測試文件是否被修改的代碼
程序需要保持跟蹤文件被生成、打開、或保存之后是否被修改過("臟的"),這樣當關閉文件或退出程序時就可以提示問用戶是否要保存操作。為此增加一個稱作dirty的布爾變量。
在源代碼中添加下列okToAbandon()方法,可將這個新方法緊放在saveAsFile()方法之后:
// Check if file is dirty. // If so get user to make a "Save? yes/no/cancel" decision. boolean okToAbandon() { int value = JOptionPane.showConfirmDialog(this, "Save changes?","Text Edit", JOptionPane.YES_NO_CANCEL_OPTION); switch (value) { case JOptionPane.YES_OPTION: // yes, please save changes return saveFile(); case JOptionPane.NO_OPTION: // no, abandon edits // i.e. return true without saving return true; case JOptionPane.CANCEL_OPTION: default: // cancel return false; } }
將在隨后完成的上面方法當用戶選擇 File|New, File|Open, 或 File|Exit時就被調用。 這個方法的目的是測試文本是否需要保存(是否動過)。若文本動過,這個方法就用Yes, No, Cancel消息對話問用戶是否保存。這個方法在用戶點選Yes按鈕時,也調用saveFile()。若這個方法返回的布爾值是true(真),則表明可以退出當前文件,因為文件是干凈的或用戶點選了Yes或No按鈕。如果返回值是false(假),意味著用戶點選了Cancel。實際檢查文件是否被改變的代碼在隨后的步驟中添加。目前這個方法總認為文件是不干凈的,即使文字根本沒被動過。隨后要添加一個當用戶在文本區域輸入文字時就將dirty變量設置為true的方法,并在okToAbandon()方法的頭部增加測試dirty變量的代碼。
添加一個清除文本區的菜單事件處理器
將File|New菜單項與清除文本區的事件處理器掛起鉤來。
void jMenuItem1_actionPerformed(ActionEvent e) { // Handle the File|New menu item. if (okToAbandon()) { // clears the text of the TextArea jTextArea1.setText(""); // clear the current filename and set the file as clean: currFileName = null; dirty = false; updateCaption(); } }
添加一個文件選擇對話框
將File|Open菜單項與提供給用戶一個文件選擇對話框的JfileChooser控件的事件處理器掛起鉤來。如果用戶選擇了一個文件,按下了OK按鈕,這個事件處理器打開那個文本文件并把文字放入JTextArea(即文本區)。
void jMenuItem2_actionPerformed(ActionEvent e) { //Handle the File|Open menu item. if (!okToAbandon()) { return; } // Use the OPEN version of the dialog, test return for Approve/Cancel if (JFileChooser.APPROVE_OPTION == jFileChooser1.showOpenDialog(this)) { // Call openFile to attempt to load the text from file into TextArea openFile(jFileChooser1.getSelectedFile().getPath()); } this.repaint(); }
添加從文件中讀出文字的代碼
添加從選定的文件中將文字實際讀到文本區JTextArea的代碼。
首先需要在用戶類中增加一個新的方法執行實際打開文件的操作,這個方法叫作openFile()。
// Open named file; read text from file into jTextArea1; report to statusBar. void openFile(String fileName) { try { // Open a file of the given name. File file = new File(fileName); // Get the size of the opened file. int size = (int)file.length(); // Set to zero a counter for counting the number of // characters that have been read from the file. int chars_read = 0; // Create an input reader based on the file, so we can read its data. // FileReader handles international character encoding conversions. FileReader in = new FileReader(file); // Create a character array of the size of the file, // to use as a data buffer, into which we will read // the text data. char[] data = new char[size]; // Read all available characters into the buffer. while(in.ready()) { // Increment the count for each character read, // and accumulate them in the data buffer. chars_read += in.read(data, chars_read, size - chars_read); } in.close(); // Create a temporary string containing the data, // and set the string into the JTextArea. jTextArea1.setText(new String(data, 0, chars_read)); // Display the name of the opened directory+file in the statusBar. statusBar.setText("Opened "+fileName); } catch (IOException e) { statusBar.setText("Error opening "+fileName); } }
替換先前所說的File|Open 事件處理器中的 if() 語句:
// Display the name of the opened directory+file in the statusBar. statusBar.setText("Opened "+jFileChooser1.getSelectedFile().getPath()); // Code will need to go here to actually load text // from file into JTextArea. with this new openFile() method instead, using the concatenated Directory and File name. // Call openFile to attempt to load the text from file into JTextArea openFile(jFileChooser1.getSelectedFile().getPath()); //repaints menu after item is selected this.repaint();
添加一個保存文件的菜單項
在選擇File|Save 和 File|Save as時,將文件寫回到磁盤的代碼。
為此,需要增加一個含有被打開文件名字的字符串例程變量和增加將文字寫回到文件或另一個文件的方法。
創建下列可從File|Save事件處理器調用的方法saveFile()。可將其放在openFile()方法之后。這個方法在保存時也將文件名寫到狀態欄。
// Save current file; handle not yet having a filename; report to statusBar. boolean saveFile() { // Handle the case where we don't have a file name yet. if (currFileName == null) { return saveAsFile(); } try { // Open a file of the current name. File file = new File (currFileName); // Create an output writer that will write to that file. // FileWriter handles international characters encoding conversions. FileWriter out = new FileWriter(file); String text = jTextArea1.getText(); out.write(text); out.close(); this.dirty = false; // Display the name of the saved directory+file in the statusBar. statusBar.setText("Saved to " + currFileName); return true; } catch (IOException e) { statusBar.setText("Error saving "+currFileName); } return false; }
創建沒有當前文件名時,從saveFile()方法中調用的saveAsFile()方法。它也可以從File|Save As 菜單調用。將下列代碼緊放在saveFile()方法之后:
// Save current file, asking user for new destination name. // Report to statuBar. boolean saveAsFile() { // Use the SAVE version of the dialog, test return for Approve/Cancel if (JFileChooser.APPROVE_OPTION == jFileChooser1.showSaveDialog(this)) { // Set the current file name to the user's selection, // then do a regular saveFile currFileName = jFileChooser1.getSelectedFile().getPath(); //repaints menu after item is selected this.repaint(); return saveFile(); } else { this.repaint(); return false; } }
菜單File|Exit, 在退出應用程序的代碼如下:
//File | Exit action performed public void jMenuFileExit_actionPerformed(ActionEvent e) { if (okToAbandon()) { System.exit(0); } }
3) 激活工具欄按鈕
如果在應用向導中選擇了Generate Toolbar(生成工具欄)選項,則Jbuilder就生成通常帶有三個JButton 按鈕(OPen File、Save File 和About) 控件且有圖標顯示的JtoolBar(工具欄)代碼。要做的就是給每個按鈕的標稱指定文字和指定工具提示文字,并為每個按鈕創建一個actionPerformed()事件,用戶從每個按鈕actionPerformed()事件中調用相應的事件處理方法。
指定按鈕工具的提示文字
對應jButton1輸入Open File 對應jButton2輸入Save File 對應jButton3輸入About
創建按鈕事件
創建對應jButton1的jButton1_actionPerformed(ActionEvent e)事件并從中調用openFile()方法:
//Handle toolbar Open button openFile();
創建對應jButton2的jButton2_actionPerformed(ActionEvent e)事件并從中調用 saveFile()方法:
//Handle toolbar Save button saveFile(); 創建對應jButton3的jButton3_actionPerformed(ActionEvent e)事件并從中調用helpAbout()方法: //Handle toolbar About button helpAbout();
創建fileOpen()方法
fileOpen()方法的目的是執行當前在File|Open菜單項處理方法中的操作。即按下Open按鈕和選擇File|Open 菜單項執行的是同樣的操作,所以創建fileOpen()方法將代碼復制一下即可。從File|Open 菜單和Open按鈕調用相同的代碼。
// Handle the File|Open menu or button, invoking okToAbandon and openFile // as needed. void fileOpen() { if (!okToAbandon()) { return; } // Use the OPEN version of the dialog, test return for Approve/Cancel if (JFileChooser.APPROVE_OPTION == jFileChooser1.showOpenDialog(this)) { // Call openFile to attempt to load the text from file into TextArea openFile(jFileChooser1.getSelectedFile().getPath()); } this.repaint(); }
創建saveFile()方法
對File|save菜單和save按鈕再做一次同樣的事情。將當前File|save事件處理器中的代碼收集到新的 saveFile()方法中,即可從菜單處理器也可從按鈕處理器對其調用。
// Save current file; handle not yet having a filename; report to statusBar. boolean saveFile() { // Handle the case where we don't have a file name yet. if (currFileName == null) { return saveAsFile(); } try { // Open a file of the current name. File file = new File (currFileName); // Create an output writer that will write to that file. // FileWriter handles international characters encoding conversions. FileWriter out = new FileWriter(file); String text = jTextArea1.getText(); out.write(text); out.close(); this.dirty = false; // Display the name of the saved directory+file in the statusBar. statusBar.setText("Saved to " + currFileName); updateCaption(); return true; } catch (IOException e) { statusBar.setText("Error saving " + currFileName); } return false; }
建helpAbout()方法
對Help|About菜單和About按鈕再做一次同樣的事情。將當前Help|About事件處理器中的代碼收集到新的 helpAbout()方法中,即可從菜單處理器也可從按鈕處理器對其調用。
// Display the About box. void helpAbout() { TextEditFrame_AboutBox dlg = new TextEditFrame_AboutBox(this); Dimension dlgSize = dlg.getPreferredSize(); Dimension frmSize = getSize(); Point loc = getLocation(); dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,(frmSize.height - dlgSize.height) / 2 + loc.y);
dlg.setModal(true); dlg.show(); }
4) 將事件處理與文本區聯系起來
將事件處理與文本區JtextArea聯系起來,這樣只要有輸入操作用戶程序就設置dirty標志為真。為此需要在JtextArea的文本模板中添加一個Swing控件DocumentListener(文本監聽器)且檢查插入、刪除和改變等事件。
DocumentListener被添加到 jbInit():
document1.addDocumentListener(new TextEditFrame_document1_documentAdapter(this));
在void document1_changedUpdate(DocumentEvent e)事件中插入下面代碼:
dirty = true;
為document1 再創建兩個事件:insertUpdate()和removeUpdate()。 在這些事件中插入在changedUpdate()事件中使用的同樣的代碼。
這樣只要在文本區輸入任何字符都將強迫dirty標志為真。
5) 在文本區添加一個右擊彈出菜單
控件DBTextDataBinder用來在Swing文本控件中添加一個執行諸如剪切、復制、粘貼等簡單編輯任務的右擊菜單。DBTextDataBinder還有一個將文件裝入JtextArea和保存文件的內部動作,但不允許用戶恢復顯示在狀態欄的裝入或保存的文件名。本例中,只是添加一個DBTextDataBinder控件給jTextArea1,不使用其中的文件打開和保存操作。
6) 在窗口的標題欄展示文件名和狀態
添加使用應用程序的標題欄顯示當前文件名和當文件受"污染"時顯示一個星花號的代碼。為此,創建一個更新標題欄的新方法,然后從代碼改變文件名或改變dirty標志的地方調用它。給這個新方法取名為updateCaption()。
updateCaption()方法:
// Update the title bar of the application to show the filename and its dirty state. void updateCaption() { String caption; if (currFileName == null) { // synthesize the "Untitled" name if no name yet. caption = "Untitled"; } else { caption = currFileName; } // add a "*" in the caption if the file is dirty. if (dirty) { caption = "* " + caption; } caption = "Text Editor - " + caption; this.setTitle(caption); }
從dirty標志被實際改變的每一個地方或者每當用戶改變當前文件名currFileName的時候調用 updateCaption()。特別要將調用 updateCaption()語句放在下列這些地方:
①在TextEditFrame()構造器的try模塊內緊接著調用jbInit()方法之后;
② 在openFile()方法的try模塊的最后一行;
③ 在saveFile()方法try模塊返回true的前一行;
④ 在File|New 菜單處理器jMenuItem1_actionPerformed()的if模塊的最后一行;
⑤當由于用戶輸入,dirty標志在干凈的文件中第一次被設置為true時。每一個文本事件處理器都應該改變為:
void document1_changedUpdate(DocumentEvent e) { if (!dirty) { dirty = true; updateCaption(); } } void document1_insertUpdate(DocumentEvent e) { if (!dirty) { dirty = true; updateCaption(); } } void document1_removeUpdate(DocumentEvent e) { if (!dirty) { dirty = true; updateCaption(); } }
2、TextEditclass.java的源程序代碼:
package texteditor; import javax.swing.UIManager; import java.awt.*;
/** * <p>Title: TextEditor</p> * <p>Description: This is a study programme</p> * <p>Copyright: Copyright (c) 2004</p> * <p>Company: ghq</p> * @author ghq * @version 1.0 */
public class TextEditClass { boolean packFrame = false;
//Construct the application public TextEditClass() { TextEditFrame frame = new TextEditFrame(); //Validate frames that have preset sizes //Pack frames that have useful preferred size info, e.g. from their layout if (packFrame) { frame.pack(); } else { frame.validate(); } //Center the window Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = frame.getSize(); if (frameSize.height > screenSize.height) { frameSize.height = screenSize.height; } if (frameSize.width > screenSize.width) { frameSize.width = screenSize.width; } frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2); frame.setVisible(true); }
//Main method public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); } catch(Exception e) { e.printStackTrace(); } new TextEditClass(); } }
上面的這段程序主要是構建 TextEditorFrame 的主窗口和主方法入口(main ()),它有下面2點編程技巧說明:
1) 設置外觀及基調
設計時的外觀和基調
如果已經把 Jbuilder的外觀和基調從其默認值改變了,則在開始使用UI設計器之前,在Jbuilder 內讓UI 設計器使用 Metal Look & Feel(金屬外觀和基調),也可以使用其它外觀和基調,但本例中選擇金屬外觀和基調,這時一種適合于跨平臺設計的選擇。
運行時的外觀和基調
在設計器的彈出菜單或Jbuilder環境選項對話框中設置的外觀和基調對運行時的用戶界面(UI)沒有任何影響。要強制一個運行時的外觀和基調,必須在應用程序(本例即為TextEditClass.java)的類的主方法(main())中設置。
作為默認,應用向導會在可運行類的main()方法中生成下列一行代碼:
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
其含義是運行時的外觀采用主機系統使用的外觀。
若是想要CDE/Motif 或 Windows 式的外觀則參數應改變為:
UIManager.setLookAndFeel ("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); 或 UIManager.setLookAndFeel ("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
2) 窗口的定義
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = frame.getSize(); if (frameSize.height > screenSize.height) { frameSize.height = screenSize.height; } if (frameSize.width > screenSize.width) { frameSize.width = screenSize.width; } frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2); frame.setVisible(true);
3、TextEditFrame_AboutBox.java的源程序代碼:
package texteditor; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; /** * <p>Title: TextEditor</p> * <p>Description: This is a study programme</p> * <p>Copyright: Copyright (c) 2004</p> * <p>Company: ghq</p> * @author ghq * @version 1.0 */ public class TextEditFrame_AboutBox extends JDialog implements ActionListener { JPanel panel1 = new JPanel(); JPanel panel2 = new JPanel(); JPanel insetsPanel1 = new JPanel(); JPanel insetsPanel2 = new JPanel(); JPanel insetsPanel3 = new JPanel(); JButton button1 = new JButton(); JLabel imageControl1 = new JLabel(); ImageIcon imageIcon; JLabel label1 = new JLabel(); JLabel label2 = new JLabel(); JLabel label3 = new JLabel(); JLabel label4 = new JLabel(); BorderLayout borderLayout1 = new BorderLayout(); BorderLayout borderLayout2 = new BorderLayout(); FlowLayout flowLayout1 = new FlowLayout(); FlowLayout flowLayout2 = new FlowLayout(); GridLayout gridLayout1 = new GridLayout(); String product = "TextEditor"; String version = "1.0"; String copyright = "Copyright (c) 2002"; String comments = "This is a study programme"; //Construct the frame public TextEditFrame_AboutBox(Frame parent) { super(parent); enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { jbInit(); } catch(Exception e) { e.printStackTrace(); } pack(); } //Component initialization private void jbInit() throws Exception { //imageLabel.setIcon(new ImageIcon(TextEditFrame_AboutBox.class.getResource("[Your Image]"))); this.setTitle("About"); setResizable(false); panel1.setLayout(borderLayout1); panel2.setLayout(borderLayout2); insetsPanel1.setLayout(flowLayout1); insetsPanel2.setLayout(flowLayout1); insetsPanel2.setBorder(new EmptyBorder(10, 10, 10, 10)); gridLayout1.setRows(4); gridLayout1.setColumns(1); label1.setText(product); label2.setText(version); label3.setText(copyright); label4.setText(comments); insetsPanel3.setLayout(gridLayout1); insetsPanel3.setBorder(new EmptyBorder(10, 60, 10, 10)); button1.setText("Ok"); button1.addActionListener(this); insetsPanel2.add(imageControl1, null); panel2.add(insetsPanel2, BorderLayout.WEST); this.getContentPane().add(panel1, null); insetsPanel3.add(label1, null); insetsPanel3.add(label2, null); insetsPanel3.add(label3, null); insetsPanel3.add(label4, null); panel2.add(insetsPanel3, BorderLayout.CENTER); insetsPanel1.add(button1, null); panel1.add(insetsPanel1, BorderLayout.SOUTH); panel1.add(panel2, BorderLayout.NORTH); } //Overridden so we can exit when windows is cancel protected void processWindowEvent(WindowEvent e) { if (e.getID() == WindowEvent.WINDOW_CLOSING) { cancel(); } super.processWindowEvent(e); } void cancel() { dispose(); } // Help|About de button is used action performed public void actionPerformed(ActionEvent e) { if (e.getSource() == button1) { cancel(); } } }
說明:上面的這段程序主要是構建Help菜單的AboutBox 對話框,顯示product、version 和comments 等內容。 至此我們已完成文本編輯器所有的菜單及代碼設計等工作,在 jbuilder9 環境下編譯運行會出現如下的Text Editor窗口:

三、從命令行運行打包程序有關說明
首先將Text Editor應用程序裝配成一個JAR文件。既然已經創建了"Text Editor" 應用程序,用戶就可以使用Jbuilder9的Archive Builder(檔案構筑器)將全部文件裝配成一個Java Archive File(JAR,Java歸檔文件)。
在從命令行運行應用程序之前,用戶必須確保操作系統的PATH環境變量指向JDK jre/bin/目錄,即Java的運行環境。Jbuilder9安裝過程保證了Jbuilder9 知道到那里找到JDK 類文件。但是若離開了Jbuilder9環境,系統需要知道運行Java時,類文件被安裝到了什么位置。如何設置PATH環境變量視用戶所用操作系統而定。要從命令行運行 Text Edit程序,步驟如下:
①切換到命令行窗口,將路徑改變到JAR文件所在的TextEditor 目錄。
② 在命令行輸入java看看Java是否在當前路徑中,若在就會顯示Java的使用和選項,若不在,就將PATH環境變量設到JDK的jre/bin/文件夾。對于Windows XP和NT/2000/2003系統,設置路徑如下: set PATH=<e:><jbuilder9><jdk>jrein
這里:
<e:> 是驅動器;
<jbuilder9>是 Jbuilder9目錄名;
<jdk>是Jbuilder安裝時提供的JDK 目錄名,例如:jbuilder9/jdk1.4/
③ 在命令行輸入下列命令:
java -jar TextEditor.jar
這里:
java ---- 運行java文件的Java工具。
jar ---- 該選項告訴 Java VM (Java虛擬機)這是一個打包文件。
TextEditor.jar ---- 包文件的名字。
由于清單文件在Main-Class頭中提供了運行那個類,所以在命令行末尾無需指定類名,并且由于所有的類、資源、和獨立件都被包含到了裝配成包的JAR文件中,所以也不需要指定類路徑classpath或將Jbuilder的庫文件復制到當前目錄。
注:一旦使用了-jar選項,Java運行時就會忽略任何顯式給出的classpath設置。
如果我們不是在 TextEditor 目錄下運行這個JAR文件,則應使用下列Java命令:
java -jar -classpath <full_path> <main_class_name>
Java運行時在JAR文件中尋找啟動類和應用程序使用的其它類,Java VM虛擬機使用三個搜尋路徑查找文件,它們是:引導類路徑、安裝時擴展路徑和用戶類路徑。
|