Tutorial for XMLPanelEdit: Java Swing GUI by XML > How to generate Java Swing GUI from XML : Abstract classes
Previous Page Contents Next Page
OOP XMLPanelEdit home page

Contact Us

How to generate Java Swing GUI from XML : Abstract classes

3.2: com.oopreserch.xml.util.XMLPanel_1_0

As you see in the previous page, we can do everything only with 'GUIParser_1_0'. But the following steps may always be the same in almost all the programs:

  1. Load the property resource file appropriate for the run-time Locale.
  2. Get the path to the intended XML from the property resource file.
  3. Parse the intended XML.
  4. Get the parsed document object from the parser.
  5. Get the 'root' element from the parsed document object.
  6. Placing the child components onto the instance of JPanel by 'setPanel(org.w3c.dom.Element el, JComponent panel)'.
In addition, our source code will need to implement 'GUIListener' interface, if our GUI has the JButtons on JToolBar. (For details about 'GUIListener', please read the related section.)

To make our development easier, 'com.oopreserch.xml.util.XMLPanel_1_0' takes most of these tasks. By the help of this class, all we have to do is:
  1. Prepare the property resource file which points the path to the intended XML.
  2. Define the sub-class of 'XMLPanel_1_0' and implements 'iniParts()' method.
  3. Override 'invokeAction(ToolBarEvent tbe)' method, if our GUI has the JButtons on JToolBar.
  4. Call 'readXML()' within our sub-class. This method generates our GUI.

The main method of 'XMLPanel_1_0' is 'readXML()'. This method works as below:

So, the source code of our sub-class of 'XMLPanel_1_0' will look like this:

   public class SubclassPanel extends XMLPanel_1_0{

      public SubclassPanel(){
         super();
         readXML();
         initParts();
      }


If we don't use 'XMLPanel_1_0', our source code will be much complicated one, as shown below:

   public class SubclassPanel extends JPanel{

      public SubclassPanel(){
         super();
         ResourceBundle res=ResourceBundle.getBundle("SubclassPanel");
         String url=res.getString("xml_url");
         GUIParser_1_0 gui=new GUIParser_1_0();
         DOMParser parser=new DOMParser();
         ErrorHandler e_diag=new XMLErrorDiag("WatchDog :XML Error");
         try{
         /*
         * Configure the parser
         */
         parser.setFeature("http://xml.org/sax/features/validation",true);
         parser.setFeature("http://apache.org/xml/features/allow-java-encodings",true);
         parser.setErrorHandler(e_diag);
         /*
         * Parse our XML document, "xml/our_gui.xml".
         */
         parser.parse(url);
         /*
         * Get the parsed document object.
         */
         org.w3c.dom.Document doc=parser.getDocument();
         /*
         * Get the 'root' element from the parsed document object.
         */
         org.w3c.dom.Element root=doc.getDocumentElement();
         /*
         * Initialize the child components and place them onto this, the instance of JPanel.
         */
         gui.setPanel(root,this);
      }
      catch(SAXException ex){
         e_diag.println(ex.toString());
      }
      catch(DOMException ex){
         e_diag.println(ex.toString());
      }
      catch(IOException ex){
         e_diag.println(ex.toString());
      }
   }


Thus, 'XMLPanel_1_0' makes our source code much easier.


3.2.1: Prepare the property resource file

As I described in the previous page, it is desirable to specify the path to the XML by the property resource file. And 'XMLPanel_1_0' takes this strategy. The 'readXML()' method of 'XMLPanel_1_0' tries to load the property resource file by the following rule:

  1. Get the Locale of the run-time environment, such as en_US or ja_JP. In usual, Locale consists of the language code and the country code.
  2. Resolve the class name of our sub-class without the package tree. For example, if our sub-class is com.foo.Bar, the name of our sub-class is resolved as Bar.
  3. Try to load NameOfSubclass_lang_country.properties, based on the language code and the country code of the Locale. The intended file name will be Bar_en_US.property or Bar_ja_JP.property, for example.
  4. In case of the failure, try to load NameOfSubclass_lang.properties, based on the language code of the Locale. The intended file name will be Bar_en.property or Bar_ja.property, for example.
  5. In case of the still failure, try to load NameOfSubclass.properties, regardless of the Locale. The intended file name will be Bar.property, for example.
For details about the suffix (the language code and the country code) of the property resource file, see the related section of JavaTutorial.

All the property resource file must point the path to the XML, and the name of this property is 'xml_url'.
For example, the property resource file for 'com.foo.Bar' will be 'Bar_en.properties' for the Locale of English language. But for the Locale of Japanese language, it will be 'Bar_ja.properties'. And these 2 property resource files will point the path to the different XML, i.e. 'Bar_en.properties' will include the line of:

xml_url=xml/GuiForEnglish.xml


and 'Bar_ja.properties' will:

xml_url=xml/GuiForJapanese.xml


By this way, we can prepare the different GUI per Locale, and the XML appropriate for the Locale will be selected at the run-time.

Because we cannot prepare the GUI for all the Locales in the world, we should always prepare the default GUI and its property resource file. In case of the above example, 'Bar.properties' is the default property resource file, because it will be loaded if the property resource file for the run-time Locale cannot be found. This default property resource file must point the path to the XML for the default GUI. In usual, the text messages (such as the text lable on JButton) on the default GUI should be written in English language, because US-Ascii characters can be rendered on all the environment. So, 'Bar.properties' will contain the line of:

xml_url=xml/GuiForEnglish.xml


Thus, don't forget to prepare the default GUI and the default property resouce file.


3.2.2: Define 'public void iniParts()'

All the subclass of 'XMLPanel_1_0' must define this method. (Note that this method is marked as 'abstract' in this Class.)

Although the 'readXML()' method initializes the child components and places them onto the instnace of JPanel, we have no reference to these child components yet.
How do we work with these child components within our sub-class? As I described in the previous page, 'GUIParser_1_0' object is also the place holder of these child components. From 'GUIParser_1_0' object, we can access the intended child components by 'getGUI(String name)' method.
The good news is that 'GUIParser_1_0' object is available within our sub-class, i.e. as one of its instance variables, 'XMLPanel_1_0' keeps the reference to 'GUIParser_1_0' object. This instance variable is 'gui'.

The 'public void iniParts()' method is the best place to work with the child components. It looks like the this:


   public void iniParts(){
      JButton button=(JButton)gui.getGUI("beep_b");
      button.addActionListener(new ActionListener(){
         public void actionPerformed(ActionEvent ev){
            System.getToolkit.beep();
         }
      });
      .....
   }


In the code above, the instance of JButton is retrieved from 'GUIParser_1_0' object. The parameter of 'getGUI(String)' method is 'beep_b'. It is the value of the 'value.name' attribute in the XML document. Let's look into the XML fragment:

   <panel.child>
      <component
         class.name="javax.swing.JButton"
         editable="false" 
         label.text="Beep"
         opaque="false"
         value.name="beep_b"
         wordwrap="false">
            <border border="RAISED"/>
      </component>
   </panel.child>


As you guess, when the user clicks 'Beep' JButton, our GUI beeps.


3.2.3: Override 'public void invokeAction(ToolBarEvent tbe)'

As I described in the previous section, we can access the child components through 'gui.getGUI(String)' and add them the event listener objects.
But JButton on JToolBar is the exception, because it is created as the 'Action' object by 'GUIParser_1_0' object. And this 'Action' object is 'MyAction' object, which calls 'invokeAction(ToolBarEvent)' method on 'GUIListener' object when the user clicks JButton on JToolBar. Given 'ToolBarEvent' object, 'GUIListener' object can know which JButton is clicked. For details about the 'GUIListener' interface, please read the previous page.

'XMLPanel_1_0' implements 'GUIListener' interface and its 'invokeAction(ToolBarEvent)' method is empty one as default. If our Java Swing GUI has JButton on JToolBar, our sub-class of 'XMLPanel_1_0' should override this method.
It look like this:


   public void invokeAction(ToolBarEvent tbe){
      /*
      * From ToolVarEvent, we can know which JButton
      * is clicked.
      */
      int act_num=tbe.getNumber();
      switch(act_num){
         case 1:
            newFile();
	    break;
         case 2:
	    openFile();
	    break;
         case 3:
	    saveFile();
	    break;
      ....


When the first button on the JToolBar is clicked, 'newFile()' is called. In case of the second JButton, 'openFile()' is called.


3.2.4: Call 'public void readXML()'

In usual, the constructor is the good place to call 'readXML()'. After the invocation of this method, 'GUIParser_1_0' object is available within our sub-class. In addition, 'ResourceBundle' object (which is loaded from the property resource file) is also available within our sub-class. This means we can safely call 'iniParst()' only after 'readXML()'. For details about 'iniParts()', please read the related section. In most cases, 'iniParts()' follows just after 'readXML()'.
Let's look into the source code of the typical constructor of the sub-class of 'XMLPanel_1_0':


   package com.foo;

   import com.oopreserch.xml.util.XMLPanel_1_0;

   public class Bar extends XMLPanel_1_0{

      public Bar(){
         super();
         readXML();
         iniParts();
      }

      public void iniParts(){
         /*
         * After 'readXML()' is called, we can access 'gui'.
         * 'gui' is 'GUIParser_1_0' object.
         */
         JButton button=(JButton)gui.getGUI("beep_b");
         button.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ev){
               System.getToolkit.beep();
            }
         });
      }

   }    


3.2.5: Call 'public void readXML(String url)'

Alternative to 'readXML()'. We may want to specify the path to the XML explicitly. In this case, please call this method instead of 'readXML()'.


3.2.6: Summary

Method(s) of Class: com.oopreserch.xml.util.XMLPanel_1_0
method argument(s) description
abstract public void iniParts() -- The subclass of this class must define this method. This is the good place to work on the child components.
For details...
public void invokeAction(ToolBarEvent tbe) ToolBarEvent tbe:
By this parameter, our sub-class can know which JButton on JToolBar is clicked. For details, please read the related section in the previous page.
This method is the member of 'com.oopreserch.xml.util.GUIListener' interface. As default, 'XMLPanel_1_0' implements this method as the empty one. Only if our sub-class has JButton on JToolBar, we should should override this method.
For details...
public void readXML() -- Load the property resource file for the run-time Locale. And parse the XML specified by 'xml_url' property. Based on the XML, create the child components and place them on JPanel.
For details...
public void readXML(String url) String url:
The path to the XML.
Similar to 'readXML()', but we can specify the path to the XML. After the XML is parsed, create the child components and place them on JPanel.
For details...

Instance variables of Class: com.oopreserch.xml.util.XMLPanel_1_0
variable name description
gui The instance of 'GUIParser_1_0'. After 'readXML()' is called, our sub-class can access to this variable. Because 'GUIParser_1_0' is the place-holder of the child components, our sub-class can work on them. 'iniParts()' method depends on this variable.
For details...
res The instance of 'java.util.ResourceBundle'. After 'readXML()' is called, our sub-class can access to this variable.
e_diag The instance of 'com.oopreserch.xml.util.ErrorDiag'. It is the implementation of 'org.w3c.dom.ErrorHandler'. In case of the problems while parsing the XML, the error dialog pops up and shows the error messages. In usual, we need not to be concerned with this variable.


3.3: com.oopreserch.xml.util.XMLFrame_1_0

Same as XMLPanel_1_0, except that this class is the subclass of 'JFrame'.
The following methods and the instance variables are just the same ones as XMLPanel_1_0:

Because this class is the sub-class of JFrame, there are the following differences:
  1. This class creates JPanel object in it, and place the child components on this JPanel. This JPanel can be referred by the instance variable of 'main'.
  2. As the subclass of 'JFrame', we can specify what it does when closing the window. This can be done by the constructor and 'protected void exitApp()' method.
In this section, I'll describe these methods and the instance variables. As for the rest of the methods and the instance variables, please read the section about 'XMLPanel_1_0'.


3.3.1: Where to place the child components

As you know, the child components like 'JButton' can be added onto the instance of JPanel. But, JFrame cannot place its child components directly on it. So, the child components should be placed on JPanel, and this JPanel must be added onto the content pane of JFrame.

The constructor of this class creates JPanel and 'readXML()' method places the child components on it. Within our sub-class, this JPanel object can be referred by 'main' variable. But, in most cases, we need not be concerned with this variable.


3.3.2: What to do when closing the window

Most GUI based program has at least one main window. In usual, JFrame plays the role of this main window. When the user closes the main window, the program should exit gracefully. To achive this, WindowListener must be added to JFrame. As a WindowListener, we usualy use WindowAdapter. And its 'windowClosing(WindowEvent e)' method is responsible for exiting the program. The typical Java Swing GUI programs have the lines like this:


   JFrame frame=new JFrame("Example");
   frame.addWindowListener(new WindowAdapter(){
      public void windowClosing(WindowEvent e) {
         System.exit(0);
      }
   });


Because the code like above is same to almost all the program, this class implements it within its constructor and 'exitApp()' method. In the subsquent 2 sub-sections, I'll describe about the constructor and 'exitApp()' method.


3.3.2.1: Constructor

This class has 2 constructors. One of them is no-argument constructor and another takes the boolean as its parameter. They are:

The first one closes the window but does not exit the progam. The instance of this class just disappears, but does not exit the program.
Given the 'true' value as its argument, the second one creates the JFrame, which calls 'exitApp()' method when the window is closed. As default, 'exitApp()' simply exits the program. But, our sub-class can override 'exitApp()'. (I'll describe about it in the next section.)
The constructor of our sub-class should call one of these constructors. It looks like this:

   public class SubclassFrame extends XMLFrame_1_0{

      public SubclassFrame(){
         super(true);
	 ...


'SubclassFrame' exits the program when the user closes the main window.


3.3.2.2: protected void exitApp()

Given the 'true' value as its argument, the two-arguments constructor creates JFrame which calls 'exitApp()' method when closed. The default implementation of 'exitApp()' simply exits the program, but we can override it as we like. For example, the word processor program should not exit if the updated document is not saved yet. In this case, 'exitApp()' should pop the dialog which asks the user to save the document.
Let's look into the source code below:


   protected void exitApp(){
      /*
      * Only when 'isUpdated' is false, the program exits.
      */
      if(isUpdated){
         popDialog();
      }
      else{
         System.exit(0);
      }
   }


3.3.3: Summary

Method(s) of Class: com.oopreserch.xml.util.XMLFrame_1_0
method argument(s) description
public XMLFrame_1_0() -- When the user closes the window, JFrame disappears, but it does not exit the progam.
For details...
public XMLFrame_1_0(boolean exitOnClose) boolean exitOnClose:
If 'true' is specified, 'exitApp()' will be called when the user closes the window. Otherwise, JFrame disappears but 'exitApp()' will not be called.
We can specify if 'exitApp()' is called or not when the user closes the window. The default implementation of 'exitApp()' just exits the progam. But we can override it.
For details...
protected void exitApp() -- The default implementation of this method just exits the progam. But we can override it. This method may or may not be called when the user closes the window. It depends on the constructor and its parameter.
For details...
abstract public void iniParts() -- Our sub-class must define this method.
For details...
public void invokeAction(ToolBarEvent tbe) ToolBarEvent tbe:
By this parameter, our sub-class can know which JButton on JToolBar is clicked. For details, please read the related section in the previous page.
Only if our sub-class has JButton on JToolBar, we should should override this method.
For details...
public void readXML() -- For details...
public void readXML(String url) String url:
The path to the XML.
For details...

Instance variables of Class: com.oopreserch.xml.util.XMLFrame_1_0
variable name description
gui For details...
res The instance of 'java.util.ResourceBundle'. After 'readXML()' is called, our sub-class can access to this variable.
main The instance of JPanel, to which the child components are added by 'readXML()' or 'readXML(String url)'. In usual, our sub-class need not to access this instance variable.
For details...
e_diag The instance of 'com.oopreserch.xml.util.ErrorDiag'. It is the implementation of 'org.w3c.dom.ErrorHandler'. In case of the problems while parsing the XML, the error dialog pops up and shows the error messages. In usual, we need not to be concerned with this variable.


3.4: com.oopreserch.xml.util.XMLDialog_1_0

Same as XMLPanel_1_0, except that this class is the sub-class of 'JDialog'.
The following methods and the instance variables are just the same ones as XMLPanel_1_0:

Because this class is the sub-class of JDialog, there are the following differences:
  1. This class creates JPanel object in it, and place the child components on this JPanel. This JPanel can be referred by the instance variable of 'main'.
  2. As the subclass of 'JDialog', we can specify the dialog is 'modal' or not. In addition, we can specify the parent window of the dialog. These can be done by the constructor.
  3. The method to pop up the dialog is required.
In this section, I'll describe these methods and the instance variables. As for the rest of the methods and the instance variables, please read the section about 'XMLPanel_1_0'.


3.4.1: Where to place the child components

As you know, the child components like 'JButton' can be added onto the instance of JPanel. But, JDialog cannot place its child components directly on it. So, the child components should be placed on JPanel, and this JPanel must be added onto the content pane of JDialog.

The constructor of this class creates JPanel and 'readXML()' method places the child components on it. Within our sub-class, this JPanel object can be referred by 'main' variable. But, in most cases, we need not be concerned with this variable.


3.4.2: The constructors

Because this class is the sub-class of JDialog, our sub-class should specify:

To make these differences, this class has the 3 constructors:
  1. public XMLDialog_1_0()
  2. public XMLDialog_1_0(boolean isModal)
  3. public XMLDialog_1_0(boolean isModal,Component parent)
When the first constructor is called, the 'modal' dialog is created. The parameter of the second constructor can specify if the dialog is 'modal' or not. By the second parameter of the last constructor, our sub-class can specify the parent window of the dialog.
The constructor of our sub-class should call one of these constructors. It looks like this:

   public class SubclassDiag extends XMLDialog_1_0{

      public SubclassDiag(Component parent) {
         /*
         * The instance of this subclass is 'modal'
         * and it appears centerred over the window
         * specified by 'parent'.
         */
         super(true,parent);
         readXML();
         setTitle(res.getString("title"));
         iniParts();
      }


3.4.3: The method to pop up the dialog

To pop up the dialog, please call 'openDiag()' method. Even if we call this method from the Thread other than the Event-Dispatching Thread, this method creates the Event-Dispatching Thread. For details about the Swing's thread-rule, please read the related documentaion available at Swing connection.


3.4.4: Summary

Method(s) of Class: com.oopreserch.xml.util.XMLDialog_1_0
method argument(s) description
public XMLDialog_1_0() -- Create the 'modal' dialog.
For details...
public XMLDialog_1_0(boolean isModal) boolean isModal:
'true' for the 'modal' dialog, otherwise 'false'.
Create the dialog. It may or may not be 'modal', depending on the parameter.
For details...
public XMLDialog_1_0(boolean isModal, Component parent) boolean isModal:
'true' for the 'modal' dialog, otherwise 'false'.
Component parent:
The parent window.
Create the dialog. It may or may not be 'modal', depending on the first parameter. The dialog will be shown over the parent window, which is specified by the second parameter.
For details...
public void openDiag() -- Always open the dialog from the Event-Dispatching Thread.
For details...
abstract public void iniParts() -- Our sub-class must define this method.
For details...
public void invokeAction(ToolBarEvent tbe) ToolBarEvent tbe:
By this parameter, our sub-class can know which JButton on JToolBar is clicked. For details, please read the related section in the previous page.
Only if our sub-class has JButton on JToolBar, we should should override this method.
For details...
public void readXML() -- For details...
public void readXML(String url) String url:
The path to the XML.
For details...

Instance variables of Class: com.oopreserch.xml.util.XMLDialog_1_0
variable name description
gui For details...
res The instance of 'java.util.ResourceBundle'. After 'readXML()' is called, our sub-class can access to this variable.
main The instance of JPanel, to which the child components are added by 'readXML()' or 'readXML(String url)'. In usual, our sub-class need not to access this instance variable.
For details...
e_diag The instance of 'com.oopreserch.xml.util.ErrorDiag'. It is the implementation of 'org.w3c.dom.ErrorHandler'. In case of the problems while parsing the XML, the error dialog pops up and shows the error messages. In usual, we need not to be concerned with this variable.

Java and all Java-based trademarks and logos are trademarks or registered of Sun Microsystems, Inc. in the United States and other countries.


Previous Page Contents Next Page
OOP XMLPanelEdit home page

Contact Us


ALL CONTENTS COPYRIGHT 2002, Jun Inamori. All rights reserved.
Any questions and comments are welcome to Jun Inamori .