明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺!

JBuilder 9 開發(fā)一個文本編輯器

[摘要]一、概述   文本編輯器是一種最常用的應(yīng)用程序,下面我們利用Jbuilder 9集成開發(fā)環(huán)境,用java語言實現(xiàn)一個簡單的文本編輯器。該文本編輯器具有讀出、寫入、編輯文本文件,可以設(shè)定文字顏色、字形和編輯區(qū)域背景顏色等基本功能。   我們首先通過Jbuilder 9項目向?qū)Ш蛻?yīng)用向?qū)?chuàng)建項目,然后...
一、概述

  文本編輯器是一種最常用的應(yīng)用程序,下面我們利用Jbuilder 9集成開發(fā)環(huán)境,用java語言實現(xiàn)一個簡單的文本編輯器。該文本編輯器具有讀出、寫入、編輯文本文件,可以設(shè)定文字顏色、字形和編輯區(qū)域背景顏色等基本功能。

  我們首先通過Jbuilder 9項目向?qū)Ш蛻?yīng)用向?qū)?chuàng)建項目,然后應(yīng)用可視化設(shè)計工具,修改UI設(shè)計,連接事件,編輯源碼以及常用控件和任務(wù)諸如菜單項、工具條、文本區(qū)域和系統(tǒng)事件等常用控件和任務(wù)的處理。涉及到具體技術(shù)有:

   用JFileChooser 對話框讓用戶選擇文本文件。

   用JtextArea讀、寫和處理文本文件中的文字。

   設(shè)置前景色和背景色。

   用dbSwing FontChooser對話框設(shè)置字型。

   在狀態(tài)欄和窗口標(biāo)題欄顯示信息。

   手工添加處理UI事件的代碼 。

   通過將代碼放在一個可被菜單項和按鈕兩個事件處理器調(diào)用的新的"幫助"方法中, 使得菜單項和按鈕執(zhí)行相同的代碼。

   給JtextArea控件增加一個右擊菜單。

   保持對文件的位置以及文件是否活動過的跟蹤,展示對文件 新建, 文件 打開, 文件 保存, 文件 另存為,編輯和退出等邏輯的處理。

   將"Text Editor" 應(yīng)用程序展開為JAR 文件。

  二、開發(fā)文本編輯器java源程序說明

  文本編輯器程序包含三個java 源程序即TextEditFrame.java、TextEditclass.java 和TextEditFrame_AboutBox.java 程序,下面將分別介紹如下:

  1、TextEditFrame.java的源程序代碼(節(jié)選部分):

  package texteditor;
  //TextEditFrame.java
  import java.awt.*;//導(dǎo)入類
  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 控件互聯(lián)網(wǎng)化:即本地化應(yīng)用程序,需要添加一行代碼以便Swing 控件JfileChooser //和JcolorChooser出現(xiàn)在程序運行的語言中
  JPanel contentPane; //設(shè)置內(nèi)容窗(contentPane)的JPanel控件
  JMenuBar menuBar1 = new JMenuBar();//創(chuàng)建菜單條并加入到框架窗體中
  JMenu menuFile = new JMenu();//創(chuàng)建File菜單和相應(yīng)的菜單項
  JMenuItem menuFileExit = new JMenuItem();
  JMenu menuHelp = new JMenu();//創(chuàng)建Help菜單和相應(yīng)的菜單項
  JMenuItem menuHelpAbout = new JMenuItem();
  JToolBar toolBar = new JToolBar();//創(chuàng)建工具條組件
  JButton jButton1 = new JButton();//創(chuàng)建按鈕組件
  JButton jButton2 = new JButton();
  JButton jButton3 = new JButton();
  ImageIcon image1;//定義圖標(biāo)
  ImageIcon image2;
  ImageIcon image3;
  JLabel statusBar = new JLabel();//創(chuàng)建標(biāo)簽組件
  BorderLayout borderLayout1 = new BorderLayout();//創(chuàng)建BorderLayout 布局器
  JScrollPane jScrollPane1 = new JScrollPane();//創(chuàng)建滾動窗控件
  JTextArea jTextArea1 = new JTextArea();//創(chuàng)建多行文本域組件
  JMenuItem jMenuItem1 = new JMenuItem();//創(chuàng)建菜單項
  JMenuItem jMenuItem2 = new JMenuItem();
  JMenuItem jMenuItem3 = new JMenuItem();
  JMenuItem jMenuItem4 = new JMenuItem();
  FontChooser fontChooser1 = new FontChooser();//創(chuàng)建字型選擇對話框
  JMenu jMenu1 = new JMenu();
  JMenuItem jMenuItem5 = new JMenuItem();
  JMenuItem jMenuItem6 = new JMenuItem();
  JMenuItem jMenuItem7 = new JMenuItem();
  JFileChooser jFileChooser1 = new JFileChooser();//創(chuàng)建文本選擇對話框
  String currFileName = null; // Full path with filename. null means new/untitled.
  boolean dirty = false;
  Document document1; //文本
  DBTextDataBinder dBTextDataBinder1 = new DBTextDataBinder();
  // True means modified text.
  //構(gòu)造架框
  public TextEditFrame() {
  enableEvents(AWTEvent.WINDOW_EVENT_MASK);
  try {
  jbInit();
  updateCaption();
  }
  catch(Exception e) {
  e.printStackTrace();
  }
  }
  //組件初始化
  private void jbInit() throws Exception {
  //三個工具欄按鈕圖標(biāo)
  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();//內(nèi)容創(chuàng)格
  document1 = jTextArea1.getDocument();//多行文本域文檔
  contentPane.setLayout(borderLayout1);//borderLayout布局器
  this.setSize(new Dimension(400, 300));//窗口大小
  this.setTitle("Text Editor");//窗口標(biāo)題
  statusBar.setText(" ");
  menuFile.setText("File");
  menuFileExit.setText("Exit");
  menuFileExit.addActionListener(new TextEditFrame_menuFileExit_ActionAdapter (this));
  //添加事件監(jiān)聽器
  menuHelp.setText("Help");
  menuHelpAbout.setText("About");
  menuHelpAbout.addActionListener(new TextEditFrame_menuHelpAbout_ActionAdapter (this));
  jButton1.setIcon(image1);//設(shè)置三個工具欄按鈕圖標(biāo),添加事件監(jiān)聽器
  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");//設(shè)置菜單,添加事件監(jiān)聽器
  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);
  //內(nèi)容窗設(shè)置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 是實現(xiàn)文本編輯器的主要程序,它有下面6點編程技巧說明:

  1) 制作一個完全充滿用戶界面頂部菜單欄和底部狀態(tài)欄之間區(qū)域的文本區(qū)

  主用戶界面容器的布局管理器需要采用邊界布局(Borderlayout)。在主容器中,含有一個叫做內(nèi)容窗(contentPane)的JPanel 控件,被改變成邊界布局,需要做的只是在內(nèi)容窗添加一個文本區(qū)控件。為此,先在內(nèi)容窗添加一個滾動窗,再在滾動窗內(nèi)放上文本區(qū)控件(jTextArea)。滾動窗提供一個帶滾動棒(JScollPane)的文本區(qū)。

  一個邊界布局的容器被分成五個區(qū)域:北、南、東、西、中。每個區(qū)域只能有一個控件,所以最多可有五個控件(注:含有多個控件的面板被認(rèn)為是一個控件)。放進(jìn)中心區(qū)域的控件完全占滿該容器控件,不被含有控件的任何其他區(qū)域所占據(jù)。例如,在本例中,工具欄占據(jù)北區(qū)(頂),狀態(tài)欄占據(jù)南區(qū)(低步),由于東西兩個區(qū)域沒有安排控件,這樣滾動窗控件占據(jù)中心區(qū)域并擴展到容器的左(西)右(東)的邊緣。

  2) 創(chuàng)建菜單File (包含New、Open、Save、Save as 和Exit菜單項),菜單Edit{包含F(xiàn)ont(字體)、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(顏色選擇)附加一個菜單項事件

  創(chuàng)建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菜單項:

   添加測試文件是否被修改的代碼

  程序需要保持跟蹤文件被生成、打開、或保存之后是否被修改過("臟的"),這樣當(dāng)關(guān)閉文件或退出程序時就可以提示問用戶是否要保存操作。為此增加一個稱作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;
  }
  }

  將在隨后完成的上面方法當(dāng)用戶選擇 File New, File Open, 或 File Exit時就被調(diào)用。 這個方法的目的是測試文本是否需要保存(是否動過)。若文本動過,這個方法就用Yes, No, Cancel消息對話問用戶是否保存。這個方法在用戶點選Yes按鈕時,也調(diào)用saveFile()。若這個方法返回的布爾值是true(真),則表明可以退出當(dāng)前文件,因為文件是干凈的或用戶點選了Yes或No按鈕。如果返回值是false(假),意味著用戶點選了Cancel。實際檢查文件是否被改變的代碼在隨后的步驟中添加。目前這個方法總認(rèn)為文件是不干凈的,即使文字根本沒被動過。隨后要添加一個當(dāng)用戶在文本區(qū)域輸入文字時就將dirty變量設(shè)置為true的方法,并在okToAbandon()方法的頭部增加測試dirty變量的代碼。

   添加一個清除文本區(qū)的菜單事件處理器

  將File New菜單項與清除文本區(qū)的事件處理器掛起鉤來。

  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(即文本區(qū))。

  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();
  }

   添加從文件中讀出文字的代碼

  添加從選定的文件中將文字實際讀到文本區(qū)JTextArea的代碼。

  首先需要在用戶類中增加一個新的方法執(zhí)行實際打開文件的操作,這個方法叫作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時,將文件寫回到磁盤的代碼。

  為此,需要增加一個含有被打開文件名字的字符串例程變量和增加將文字寫回到文件或另一個文件的方法。

  創(chuàng)建下列可從File Save事件處理器調(diào)用的方法saveFile()?蓪⑵浞旁趏penFile()方法之后。這個方法在保存時也將文件名寫到狀態(tài)欄!          

  // 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;
  }

  創(chuàng)建沒有當(dāng)前文件名時,從saveFile()方法中調(diào)用的saveAsFile()方法。它也可以從File Save As 菜單調(diào)用。將下列代碼緊放在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, 在退出應(yīng)用程序的代碼如下:

  //File Exit action performed
  public void jMenuFileExit_actionPerformed(ActionEvent e) {
  if (okToAbandon()) {
  System.exit(0);
  }
  }

  3) 激活工具欄按鈕

  如果在應(yīng)用向?qū)е羞x擇了Generate Toolbar(生成工具欄)選項,則Jbuilder就生成通常帶有三個JButton 按鈕(OPen File、Save File 和About) 控件且有圖標(biāo)顯示的JtoolBar(工具欄)代碼。要做的就是給每個按鈕的標(biāo)稱指定文字和指定工具提示文字,并為每個按鈕創(chuàng)建一個actionPerformed()事件,用戶從每個按鈕actionPerformed()事件中調(diào)用相應(yīng)的事件處理方法。

   指定按鈕工具的提示文字

   對應(yīng)jButton1輸入Open File
   對應(yīng)jButton2輸入Save File
   對應(yīng)jButton3輸入About

   創(chuàng)建按鈕事件

   創(chuàng)建對應(yīng)jButton1的jButton1_actionPerformed(ActionEvent e)事件并從中調(diào)用openFile()方法:

  //Handle toolbar Open button
  openFile();

   創(chuàng)建對應(yīng)jButton2的jButton2_actionPerformed(ActionEvent e)事件并從中調(diào)用 saveFile()方法:

  //Handle toolbar Save button
  saveFile();
  創(chuàng)建對應(yīng)jButton3的jButton3_actionPerformed(ActionEvent e)事件并從中調(diào)用helpAbout()方法:
  //Handle toolbar About button
  helpAbout();

    創(chuàng)建fileOpen()方法

  fileOpen()方法的目的是執(zhí)行當(dāng)前在File Open菜單項處理方法中的操作。即按下Open按鈕和選擇File Open 菜單項執(zhí)行的是同樣的操作,所以創(chuàng)建fileOpen()方法將代碼復(fù)制一下即可。從File Open 菜單和Open按鈕調(diào)用相同的代碼。

  // 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();
  }

   創(chuàng)建saveFile()方法

  對File save菜單和save按鈕再做一次同樣的事情。將當(dāng)前File save事件處理器中的代碼收集到新的 saveFile()方法中,即可從菜單處理器也可從按鈕處理器對其調(diào)用。

  // 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按鈕再做一次同樣的事情。將當(dāng)前Help About事件處理器中的代碼收集到新的 helpAbout()方法中,即可從菜單處理器也可從按鈕處理器對其調(diào)用。

  // 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) 將事件處理與文本區(qū)聯(lián)系起來

  將事件處理與文本區(qū)JtextArea聯(lián)系起來,這樣只要有輸入操作用戶程序就設(shè)置dirty標(biāo)志為真。為此需要在JtextArea的文本模板中添加一個Swing控件DocumentListener(文本監(jiān)聽器)且檢查插入、刪除和改變等事件。

   DocumentListener被添加到 jbInit():

  document1.addDocumentListener(new TextEditFrame_document1_documentAdapter(this));

   在void document1_changedUpdate(DocumentEvent e)事件中插入下面代碼:

  dirty = true;

   為document1 再創(chuàng)建兩個事件:insertUpdate()和removeUpdate()。 在這些事件中插入在changedUpdate()事件中使用的同樣的代碼。

  這樣只要在文本區(qū)輸入任何字符都將強迫dirty標(biāo)志為真。

  5) 在文本區(qū)添加一個右擊彈出菜單

  控件DBTextDataBinder用來在Swing文本控件中添加一個執(zhí)行諸如剪切、復(fù)制、粘貼等簡單編輯任務(wù)的右擊菜單。DBTextDataBinder還有一個將文件裝入JtextArea和保存文件的內(nèi)部動作,但不允許用戶恢復(fù)顯示在狀態(tài)欄的裝入或保存的文件名。本例中,只是添加一個DBTextDataBinder控件給jTextArea1,不使用其中的文件打開和保存操作。

  6) 在窗口的標(biāo)題欄展示文件名和狀態(tài)

  添加使用應(yīng)用程序的標(biāo)題欄顯示當(dāng)前文件名和當(dāng)文件受"污染"時顯示一個星花號的代碼。為此,創(chuàng)建一個更新標(biāo)題欄的新方法,然后從代碼改變文件名或改變dirty標(biāo)志的地方調(diào)用它。給這個新方法取名為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標(biāo)志被實際改變的每一個地方或者每當(dāng)用戶改變當(dāng)前文件名currFileName的時候調(diào)用 updateCaption()。特別要將調(diào)用 updateCaption()語句放在下列這些地方:

 、僭赥extEditFrame()構(gòu)造器的try模塊內(nèi)緊接著調(diào)用jbInit()方法之后;

 、 在openFile()方法的try模塊的最后一行;

 、 在saveFile()方法try模塊返回true的前一行;

 、 在File New 菜單處理器jMenuItem1_actionPerformed()的if模塊的最后一行;

 、莓(dāng)由于用戶輸入,dirty標(biāo)志在干凈的文件中第一次被設(shè)置為true時。每一個文本事件處理器都應(yīng)該改變?yōu)椋?

  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();
  }
  }

  上面的這段程序主要是構(gòu)建 TextEditorFrame 的主窗口和主方法入口(main ()),它有下面2點編程技巧說明:

  1) 設(shè)置外觀及基調(diào)

  設(shè)計時的外觀和基調(diào)

  如果已經(jīng)把 Jbuilder的外觀和基調(diào)從其默認(rèn)值改變了,則在開始使用UI設(shè)計器之前,在Jbuilder 內(nèi)讓UI 設(shè)計器使用 Metal Look & Feel(金屬外觀和基調(diào)),也可以使用其它外觀和基調(diào),但本例中選擇金屬外觀和基調(diào),這時一種適合于跨平臺設(shè)計的選擇。

  運行時的外觀和基調(diào)

  在設(shè)計器的彈出菜單或Jbuilder環(huán)境選項對話框中設(shè)置的外觀和基調(diào)對運行時的用戶界面(UI)沒有任何影響。要強制一個運行時的外觀和基調(diào),必須在應(yīng)用程序(本例即為TextEditClass.java)的類的主方法(main())中設(shè)置。

  作為默認(rèn),應(yīng)用向?qū)诳蛇\行類的main()方法中生成下列一行代碼:

  UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

  其含義是運行時的外觀采用主機系統(tǒng)使用的外觀。

  若是想要CDE/Motif 或 Windows 式的外觀則參數(shù)應(yīng)改變?yōu)椋?

  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();
  }
  }
  }


  說明:上面的這段程序主要是構(gòu)建Help菜單的AboutBox 對話框,顯示product、version 和comments 等內(nèi)容。
  
  至此我們已完成文本編輯器所有的菜單及代碼設(shè)計等工作,在 jbuilder9 環(huán)境下編譯運行會出現(xiàn)如下的Text Editor窗口:



  三、從命令行運行打包程序有關(guān)說明

  首先將Text Editor應(yīng)用程序裝配成一個JAR文件。既然已經(jīng)創(chuàng)建了"Text Editor" 應(yīng)用程序,用戶就可以使用Jbuilder9的Archive Builder(檔案構(gòu)筑器)將全部文件裝配成一個Java Archive File(JAR,Java歸檔文件)。

  在從命令行運行應(yīng)用程序之前,用戶必須確保操作系統(tǒng)的PATH環(huán)境變量指向JDK jre/bin/目錄,即Java的運行環(huán)境。Jbuilder9安裝過程保證了Jbuilder9 知道到那里找到JDK 類文件。但是若離開了Jbuilder9環(huán)境,系統(tǒng)需要知道運行Java時,類文件被安裝到了什么位置。如何設(shè)置PATH環(huán)境變量視用戶所用操作系統(tǒng)而定。要從命令行運行 Text Edit程序,步驟如下:

 、偾袚Q到命令行窗口,將路徑改變到JAR文件所在的TextEditor 目錄。

  ② 在命令行輸入java看看Java是否在當(dāng)前路徑中,若在就會顯示Java的使用和選項,若不在,就將PATH環(huán)境變量設(shè)到JDK的jre/bin/文件夾。對于Windows XP和NT/2000/2003系統(tǒng),設(shè)置路徑如下:
  set PATH=<e:><jbuilder9><jdk>jrein

  這里:

   <e:> 是驅(qū)動器;

   <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或?qū)builder的庫文件復(fù)制到當(dāng)前目錄。

  注:一旦使用了-jar選項,Java運行時就會忽略任何顯式給出的classpath設(shè)置。

  如果我們不是在 TextEditor 目錄下運行這個JAR文件,則應(yīng)使用下列Java命令:

  java -jar -classpath <full_path> <main_class_name>

  Java運行時在JAR文件中尋找啟動類和應(yīng)用程序使用的其它類,Java VM虛擬機使用三個搜尋路徑查找文件,它們是:引導(dǎo)類路徑、安裝時擴展路徑和用戶類路徑。