|
|
How to generate Java Swing GUI from XML : Abstract classes
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:
The main method of 'XMLPanel_1_0' is 'readXML()'. This method works as below:
public class SubclassPanel extends XMLPanel_1_0{
public SubclassPanel(){
super();
readXML();
initParts();
}
|
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());
}
}
|
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:
xml_url=xml/GuiForEnglish.xml |
xml_url=xml/GuiForJapanese.xml |
xml_url=xml/GuiForEnglish.xml |
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();
}
});
.....
}
|
<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 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;
....
|
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();
}
});
}
}
|
Alternative to 'readXML()'. We may want to specify the path to the XML explicitly. In this case, please call this method instead of 'readXML()'.
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... |
| 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. |
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:
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.
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);
}
});
|
This class has 2 constructors. One of them is no-argument constructor and another takes the boolean as its parameter. They are:
public class SubclassFrame extends XMLFrame_1_0{
public SubclassFrame(){
super(true);
...
|
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);
}
}
|
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... |
| 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. |
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:
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.
Because this class is the sub-class of JDialog, our sub-class should specify:
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();
}
|
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.
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... |
| 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.
|
|
ALL CONTENTS COPYRIGHT 2002, Jun Inamori. All rights reserved.
Any questions and comments are welcome to
Jun Inamori
.