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

Contact Us

How to generate Java Swing GUI from XML : GUIParser_1_0

3:Classes for generating GUI

Once we write our Java Swing GUI into XML, the next step is to generate the actual GUI from the XML. There are 4 classes available for generating GUI from our XML documents. They are:

In this page, I'll explain how to use the first one ('GUIParser_1_0'). It is the core class of this Java API, and the last 3 classes fully depends on it. In usual, you need not to be concerned with this class, because the last 3 classes make your development much easier. But, please be patient. Reading this page will help you to understand the last 3 classes well.


3.1: com.oopreserch.xml.util.GUIParser_1_0

This is the core class for generating the actual GUI.
This class acts as

It also stores the 'GUIListener' object as one of its instance variables. When the button on JToolBar is clicked, this 'GUIListener' object takes the appropriate action.

3.1.1: The GUI generator

The related method is:

   public synchronized void setPanel(org.w3c.dom.Element, JComponent)

Given the 'root' element of the parsed document object, the method creates the child components and place them onto the specified JPanel.
For example, our source code fragments will look like this:

   /*
   * The child components are added onto 'panel'.
   */ 
   JPanel panel=new JPanel();
   GUIParser_1_0 gui=new GUIParser_1_0();
   gui.addGUIListener(this);
   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("xml/our_gui.xml");
      /*
      * 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
      * on to 'panel', the instance of JPanel.
      */
      gui.setPanel(root,panel);
   }
   catch(SAXException ex){
      e_diag.println(ex.toString());
   }
   catch(DOMException ex){
      e_diag.println(ex.toString());
   }
   catch(IOException ex){
      e_diag.println(ex.toString());
   }


In the code above, you may have the questions about the line of

   gui.addGUIListener(this);


especially about the parameter of 'this'. But please be patient. I'll explain about this in later.

Given the 'root' element of our XML document, we can call 'setPanel(org.w3c.dom.Element el, JComponent panel)' at anytime and anywhere in our programs. This means our Java Swing GUI can be altered on the fly! The best example is 'GUIViewDiag' on the XML editor, by which we can pre-view our working Java Swing GUI. It's source code fragments looks like this:


   public void setGUI(org.w3c.dom.Element root){
      // 'gui_panel' is the JPanel on the dialog.
      gui_panel.removeAll();
      gui_panel.setBorder(null);

      // 'gui' is the 'GUIParser_1_0' object.
      // 'root' is the root element of the working XML.
      gui.setPanel(root,gui_panel);
      gui_panel.validate();


When we click the 'View' button on the XML editor, the editor gets the 'root' element of the working XML and pass it into the 'GUIViewDiag'. By this way, 'GUIViewDiag' can represents the working Java Swing GUI.

In the above source code fragment, the path to the intended XML is hard-coded. But, we can write the path to the XML in the property resource file. The source code will look like this:

   /*
   * Load the property resource file for the Locale
   * of the run-time environment.
   */
   ResourceBundle res=ResourceBundle.getBundle("SubclassPanel");
   /*
   * Read the path to the intended XML from the property
   * resource file.
   */
   String url=res.getString("xml_url");

   JPanel panel=new JPanel();
   GUIParser_1_0 gui=new GUIParser_1_0();
   gui.addGUIListener(this);
   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, which is specified by
      * the property resource file.
      */
      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
      * on to 'panel', the instance of JPanel.
      */
      gui.setPanel(root,panel);
   }
   catch(SAXException ex){
      e_diag.println(ex.toString());
   }
   catch(DOMException ex){
      e_diag.println(ex.toString());
   }
   catch(IOException ex){
      e_diag.println(ex.toString());
   }

The contents of 'SubclassPanel_en.properties' will have the lines like below:
xml_url=xml/SubclassPanelForEnglish.xml
but 'SubclassPanel_fr.properties' may include the line like:
xml_url=xml/SubclassPanelForFrench.xml
Note that 'xml/SubclassPanelForFrench.xml' may contain the French text which will be displayed on our Swing GUI.
By this strategy, 'DOMParser' can read the appropriate XML for the Locale of the run-time environement. It is very useful for the localization of our Java Swing GUI.

For details about the internationalization based on property resource file, please read the related section of JavaTutorial.

3.1.2: The dictionary holding the child components

The related method is:


   public JComponent getGUI(String)


The instance of this class also acts as the dictionary of the child components. The name of each child component is specified by the XML, and this name can be used as the parameter of this method.
For example, our source code will look like this:

   JButton close_b=(JButton)gui.getGUI("close_b");
   close_b.addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent ev){
         closeChild();
      }
   });


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

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


The root JPanel can have another nested JPanel as its child component. In this case, please use the value of the 'panel.name' attribute of the nested JPanel, instead of the value of 'value.name' attribute.

As I'll describe in the next section, the 'Action' object (which appear as JButtons on JToolBar) can be retrieved by 'getAction(String)' method. This 'Action' object can be added into 'JMenu'. Then, the same 'Action' object will also be 'JMenuItem'. By this way, the pair of JButton and JMenuItem can have the same function, and they can be enabled/disabled at the same time. For example, our source code will look like this:

   Action f_new_action=(Action)gui.getAction("f_new_b");
   JMenu f_menu=new JMenu("File");
   f_menu.add(f_new_action);


and the XML will have the following fragments:

   <toolbar.child>
      <action
         value.name="f_new_b"
         label.text="New"
         label.image="image/new.gif"/>
   </toolbar.child>


In this example, the same JButton (which is labeled as "New" and has the icon on it) will appear on both of JToolBar and JMenu.

But, on the JToolBar, we may want JButton only with the icon. In this case, please also use 'getGUI(String)'. For example, our source code may be:

   Action f_new_action=(Action)gui.getAction("f_new_b");
   JButton f_new_button=(JButton)gui.getGUI("f_new_b");
   JMenu f_menu=new JMenu("File");
   (f_menu.add(f_new_action)).setText(f_new_button.getText());
   f_new_button.setText("");


By this way, JButton on JToolBar has only the icon on it, but the corresponding JMenuItem has only the text.

3.1.3: The dictionary holding the 'Action' objects

The related method is:


   public Action getAction(String)


If Java Swing GUI has JToolBar as one of its child components, this class acts as the dictionary for 'Action' object. By this method, we can get 'Action' object using its name as the parameter.
(Note that the 'Action' object can be added onto 'JToolBar' and appears as JButton on the JToolBar.)

   Action newfile_action=gui.getAction("new_a");
   JMenu f_menu=new JMenu("File");
   f_menu.add(newfile_action);


In the code above, the 'Action' object is retrieved from the 'GUIParser_1_0' object. The parameter of 'getAction(String)' method is 'new_a'. It is the value of the 'value.name' attribute in the XML:

   <toolbar.child>
      <action
         label.text="NewFile"
         opaque="false"
         value.name="new_a">
            <border border="RAISED"/>
      </action>
   </toolbar.child>


By this way, the same JButton (which is labeled as "New" and has the icon on it) will appear on both of JToolBar and JMenu.

3.1.4: About GUIListener interface

The related method is:


   public void addGUIListener(GUIListener)


The related interface is:

   com.oopreserch.xml.util.GUIListener


And the related class is:

   com.oopreserch.xml.util.ToolBarEvent


The 'GUIListener' interface is the very simple one, which has just one method:

   public void invokeAction(ToolBarEvent)


The instance of 'GUIListener' interface is passed as the parameter of:

   addGUIListener(GUIListener)


of 'GUIParser_1_0' object. Then, 'GUIParser_1_0' object keeps it as one of the instance variables. In this subsection, I'll explain why this is required and how this interface should be implemented.
As I described above, our source code can set the event listener objects for each child components. But, how can we define the 'actionPerformed(ActionEvent e)' of the 'Action' object?
For the set of 'Action' objects (which are defined as the child components of JToolBar in the XML), 'GUIParser_1_0' object creates a series of 'MyAction' objects (the implementations of 'Action' interface). Because the 'MyAction' object implements 'Action' interface, it appears as as JButton's on JToolBar and we can place it on JMenu.
During the creation of these 'MyAction' objects, 'GUIParser_1_0' allocates the incremented number to each 'MyAction' object. For the first 'MyAction' object, 1 is allocated. And for the second one, 2 is allocated.
When the JButton on the JToolBar is clicked, the 'actionPerformed(ActionEvent e)' is called on 'MyAction' object . Then, 'MyAction' object calls 'invokeAction(ToolBarEvent tbe)' on 'GUIListener' object. The constructor of 'ToolBarEvent' takes the number of 'MyAction' object as its parameter. And 'ToolBarEvent' implements:
   getNumber()

method, which returns the number specified by the constructor. For example, if the first JButton on JToolBar is clicked, 'getNumber()' method of 'ToolBarEvent' object returns 1. In case of the second JButton, it returns 2. By this way, 'GUIListener' can know which JButton is clicked.

By this strategy, our source code will look like this:

public class SomeFrame
    extends JFrame implements GUIListener{
	....
    public SomeFrame(){
	JPanel panel=new JPanel();
	String url="xml/our_gui.xml";
	GUIParser_1_0 gui=new GUIParser_1_0();
	gui.addGUIListener(this);
	....
    }
    	....

    public void invokeAction(ToolBarEvent tbe){
    	int act_num=tbe.getNumber();
	switch(act_num){
	case 1:
	    newFile();
	    break;
	case 2:
	    openFile();
	    break;
	case 3:
	    saveFile();
	    break;
	....

    public void newFile(){
        ...
    }

    public void openFile(){
        ...
    }

    public void saveFile(){
        ...
    }

    ...


When the 1st JButton on the JToolBar is clicked, 'newFile()' is called. In case of the 2nd JButton, 'openFile()' is called.
It is easy, isn't it?

3.1.5: Summary

Method(s) of Class: com.oopreserch.xml.util.GUIParser_1_0
method argument(s) description
public synchronized void setPanel(org.w3c.dom.Element el, JComponent panel) org.w3c.dom.Element el:
The 'root' element of the parsed document object. This element is retrieved by 'getDocumentElement()' of org.w3c.dom.Document.
JComponent panel:
The child components are added to this JComponent. Currently this argument must be the instance of JPanel.
Based on the XML (which is specified by the first parameter), this method creates the child components. And these child components are placed on the JPanel (which is specified by the second parameter).
For details...
public JComponent getGUI(String name) String name:
The value of the 'value.name' attribute of the intended child component.
Return the child component, as the instance of 'JComponent'. The retrieved instance of 'JComponent' can be casted to the appropriate class. Then, our source code can add the event listener object to it.
For details...
public Action getAction(String name) String name:
The value of the 'value.name' attribute of the intended 'Action' object.
Return the instance of 'Action'. The returned 'Action' object can be added into 'JMenu'.
For details...

Method(s) of interface: com.oopreserch.xml.util.GUIListener
method argument(s) description
public void invokeAction(ToolBarEvent tbe) ToolBarEvent tbe:
A series of 'Action' objects are numbered. For example, the 'Action' object for the first JButton on JToolBar is numbered as 1. For the second JButton on JToolBar, the 'Action' object is numbered as 2. The 'getNumber()' method of ToolBarEvent returns this number. By this number, this interface can know which JButton on the JToolBar is clicked.
All the implementations of this interface must define this method.
For details...

Method(s) of Class: com.oopreserch.xml.util.ToolBarEvent
method argument(s) description
public int getNumber() -- A series of 'Action' objects are numbered. For example, the 'Action' object for the first JButton on JToolBar is numbered as 1. For the second JButton on JToolBar, the 'Action' object is numbered as 2. The 'getNumber()' method of ToolBarEvent returns this number. By this number, 'GUIListener' interface can know which JButton on the JToolBar is clicked.
For details...

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 .