|
|
|
Last
revision of this document: |
This
step of the tutorial introduces a method to recursively go through
all elements making a GUI in Java.
So each element is checked if
there are properties defined in the XML-structure. This XML-structure
was read in the previous step (JS_FC01f - Base-Class for reading a
file with XML-structure).
Then,
for elements of type JLabel and JText methods are defined to transfer
the properties defined in the XML-structure to the fitting
element.
Methods for other element-types (e.g. JButton) will be
covered in later steps of this tutorial.
Java
allows this algorithm as it has the concept of a 'Container'.
'Container' is a superclassfor all elements that can be a
'parent' of another element. Therefore it is easy to write a method
that goes recursively through the the 'tree' of elements which alway
starts with an element of type 'JFrame'.
Preface:This
step of the tutorial introduces a convenient method - which is
optimized too !
Convenient therefore as only one call of the
method within a frame covers each element.
Furthermore all
parameters needed are derived from the frame (if it is passed as a
correct parameter) where the method is called from. This minimizes
the danger of passing wrong parameters (e.g. a wrong name of the
element after a 'copy and paste' of an existing element) and
'reading' the wrong properties out of the XML-structure.
Also,
a class with static methods is introduced. 'Static methods' can be
called without first 'constructing' the class.
This simplifies the
coding for methods which do not rely on variables which have to be
kept (within the class) after the method finished.
The
code written in this tutorial is highly optimized !
It is not
essential that you understand the code for getting an idea how
Fat-Clients are developed.
Credits:Several
and none; using recursive structures is a common process - I just
applied it for that special case.
JS_FC01f
- Base-Class for reading a file with XML-structure
completed
- and its prerequisites too.
Recommended:
Structure
of the xml-file with language-dependant strings for the
user-interface read.
This
introduces the structure of the xml-tree with text-elements for the
GUI.
Building
a GUI in Java using Panels read.
This introduces the tree-structure (parent-child-relationship)
of elements forming a GUI in Java.
Create
the class JSBS_FrameServices:This
class hold static methods that perform services related to
frames.
More explanation follows later when the first method is
coded.
Right
click onto the project 'JS_Base' and select
>New>Class
Enter
the Package (js_base.frame),
the (Class-)Name (JSBS_FrameServices)
select (o) public,
do not check any boxes,
leave
the default Superclass (java.lang.Object)
and
click the [ Finish ] button.
Eclipse
has already generated a template and the individual code can be
entered.
For a listing of the complete code please refer to
Code
for JSBS_FrameServices
.
As
we have to deal with objects of the package java.awt and
javax.swing, these packages have to be imported -
and it is a
good time to enter the description too:package
js_base.frame;
import
java.awt.*;
import
javax.swing.*;
/**
*
* @author kurt@javascout.biz
*
@date 2006-05-03
*
* @description
* Class
with static methods providing utilities around the
classes
* JSBS_StartFrame and
JSBS_DetailFrame.
*
* @change-log
*
when who why
*
--------------------------------------------------------
*
*/public
class JSBS_FrameServices
{
Code
the method processLanguageDependantElement(.
. .):First
a little bit of theory what this method should do:
* The
java elements 'Component' and 'Container' are superclasses for each
element that is visible on a GUI.
A 'Container'
can be parent of one or more 'Components' - this reflects the system
how a GUI is constructed in Java:
a Jframe
contains one JPanel (the 'ContentPane', a JPanel contains other
JPanels, JLabels, JTextFields, JButtons, etc.
For
the documentation of SUN please see
http://java.sun.com/j2se/1.4.2/docs/api/java/awt/Container.html.
* Starting
with the 'ContentPane' the algorithm can handle down the structure
and inspect each element for its type (JPanel,
JLabel, JTextField, etc.).
* If language specific
properties need to be set for the identified type, the suitable
method,
which is coded within the class
JSBS_XML_DisplayStrings, is called with the identified type as one of
the parameters.
As
parameters are passed:
* The class-name of the frame
(as String);
this
is one search-argument to find the properties within the
XML-structure.
* The class derived from the
JSBS_StartFrame (usually
named xxxx_CommandCenter);
this
contains the XML-structure with the language dependant
elements.
* The Java-GUI-element of superclass
Container;
which
will be inspected for its type and if it contains 'Components'
Now
it is time to code the method that recursively inspects: public
class JSBS_FrameServices{
/*}
*
Method to recursively search the structure */ private
static int
processLanguageDependantElements(
String
parmFrameClassName, JSBS_StartFrame
parmfrmJSBS_StartFrame,) { Container
parmContainer/* Return-Code
to pass the status, that was reported by called methods, back
*/ int
intStatusCode = 0;/* }
* Check
what type is the 'Container' of and call the suitable method
*/ if
(parmContainer instanceof
JLabel) {/* implement
call to appropriate method later */ }
return
intStatusCode;
/* */ if
(parmContainer instanceof
JTextField) {/* implement
call to appropriate method later */ } return
intStatusCode;
/*
* Get
child-elements and call this method recursively */ Component
comps[] = parmContainer.getComponents();
for
(int
i = 0; i < comps.length; i++)
{
Component comp
= comps[i]; }if
(comp instanceof
Container) {
int
locintStatusCode
=
processLanguageDependantElements(parmFrameClassName,
);
parmfrmJSBS_StartFrame,
(Container)
comp/* }
* Check
if another Code than 0 (OK) was returned and keep it in that case
*/ if
(locintStatusCode
> 0) intStatusCode
= loc;intStatusCode
/*
* Return
the Status to the caller */ return
intStatusCode;
As
you might have noticed, the method above is defined.
private
So
a 'wrapper' is needed which can be called from methods belonging to
other classes.
The wrapper written here is for a call from class
JSBS_StartFrame (and derived classes).
Please see the comments
for an explanation of the code./*
*
Wrapper-method to be called from classes derived from
JSBS_StartFrame */ public
static int processLanguageDependantElements(JSBS_StartFrame
parmfrmJSBS_StartFrame) { }/* Return-Code
to pass the status, that was reported by called methods, back
*/intStatusCode = 0;int
/* /* local
StatusCode for comparisons */locintStatusCode = 0;int
* Call
the method that sets the text into the TitleBar of the frame
*/
/* Not yet implemented - comment out for
now//locintStatusCode
=
//;parmfrmJSBS_StartFrame.structJSBS_XML_DisplayStrings.processJFrame()parmfrmJSBS_StartFrame/* Check
if another Code than 0 (OK) was returned and keep it in that case
*//* (if
loc> 0) intStatusCode
intStatusCode
=;locintStatusCode
/*
* Get
the 'ClassName' of the passed parameter - it is used in the next
method-call */ String
locstrClassName =
parmfrmJSBS_StartFrame.getClass().getName().trim();
* Get
the 'ContentPane' and call the method that inspects it recursive
*/ Container
locContainer = parmfrmJSBS_StartFrame.getContentPane();
locintStatusCode
=
processLanguageDependantElements;(
locstrClassName,
)parmfrmJSBS_StartFrame,
locContainer/* Check
if another Code than 0 (OK) was returned and keep it in that case
*/
(if
loc> 0) intStatusCode
intStatusCode
=;locintStatusCode
/*
* Return
the Status to the caller */
return
intStatusCode;
Call
the recursive method after the frame was build:The
method coded in the previous paragraphs has to be called after the
frame is build in the class .JS_ErrDB_CommandCenter
This
requieres additional code at 3 places.
Please notice, that at the
import of the packages the line import
js_base.frame.JSBS_StartFrame;
was
replaced by .
This was done to include the classimport
js_base.frame.*;
too.JSBS_FrameServices
package
js_errdb.clientframes;
import
java.awt.*;
import
javax.swing.*;
import
js_base.frame.*;
import
js_base.structures.*;
import
js_base.xml.*;
/**.
. . . . . . . . . . ..
. . . . . . . . . . . public
JS_ErrDB_CommandCenter(String
parmstrLanguageCode){
super(); initialize_before_frame(String
parmstrLanguageCode);
initialize_frame; initialize_after_frame; }
.
. . . . . . . . . . .
. . . . . . . . . . . . private
void initialize_frame()
{
setVisible(true);
setSize(600,
400);
setTitle(„JavaScout-Tutorial
– Fat-Client-01 – Maintain
Error-Messages“); setContentPane(get_pnl_Main()); } private
void initialize_after_frame()
{
JSBS_FrameServices.processLanguageDependantElements(this);
}
//*
*
@param args
*/public
static void main(String[] args)
{
String locstrLanguageCode =
„“;
.
. . . . . . . . . . .
. . . . . . . . . . . .
Create
the file 'DisplayStrings.xml' and edit the content:
Before
we continue with Java-code, the file which should be read has to be
created in the folder 'TEXT.en' and edited.
To
create a new folder,
Right
click onto the project 'JS_FC01' and select
>New>Folder
Please
obey upper- and lowercase letters as the Constant 'TEXT' is defined
in the interface JSBS_UniversalParameters_Constants
and 'en' is passed as a command-line-parameter when the application
is started.
Enter the Folder name (TEXT.en),
and click the [ Finish ] button.
To
create a new file under the folder, Right
click onto the just created folder 'TEXT.en' and select
>New>File
Please
obey upper- and lowercase letters as the Constant
'DisplayStrings.xml' is defined in the interface
JSBS_UniversalParameters_Constants.
Enter
the File name (DisplayStrings.xml),
and click the [ Finish ] button.
Eclipse
has already generated an empty file and the structure can be
entered.
For a listing of the complete code please refer to
Structure
of the xml-file with language-dependant text-elements for the
user-interface
.
To
complete this step it is sufficient to code just the part for the
TitleText of the frame.
(Methods needing other values will be
covered in the next step - and then the values will be added.)<!--
Root-Element; has to be there otherwise the parser reports an error
-->
<root><!--
*********************************************
--></root><!--
********** Section with individual values for the frames ***********
-->
<FrameIndividual> <Frame> <FrameClass>js_errdb.clientframes.JS_ErrDB_CommandCenter </Frame></FrameClass> <FrameTitle></FrameTitle>CommandCenter
- Maintain Error-DB; ©
www.javascout.biz
</FrameIndividual>
Code
the method processJFrame(. . .):
This
method belongs to class JSBS_XML_DisplayStrings
(package 'js_base.xml').
It searches the XML-structure for
the fitting <FrameClass> (the frame was passed as parameter),
then takes the value from <FrameTitle> and
transfers
the value (of type String) to the 'Title' of the frame (passed as
parameter)
As
the properties for the given frame might not be present, the method
has to return a status.
The status-code is defined in the
interface JSBS_XML_Constants
:
/*
*
NOT_WELL_FORMED: Content of the file violates XML-syntax
*/ public
static int CONST_NOT_WELL_FORMED
=
2;/*
*
Stati concerning <Frame> properties within the XML-structure.
*//*
* FRAMEINDIVIDUAL_DIVISION_NOT_PRESENT:
*
There is no <FrameIndividual> division as a direct child of
the root-element. */ public
static int CONST_FRAMEINDIVIDUAL_DIVISION_NOT_PRESENT
=
11;/*
*
FRAMECLASS_NOT_PRESENT:
* A <Frame> with the searched
<FrameClassName> is not present within the XML-structure.
*/ public
static int CONST_FRAMECLASS_NOT_PRESENT
=
12;/*
*
FRAMETITLE_NOT_PRESENT:
* The property <FrameTitle>
is not present for the searched <FrameClassName>.
*/ public
static int CONST_FRAMETITLE_NOT_PRESENT
/* */=
13;/*
*
UNKNOWN_ERROR: Something went wrong but exact reason is unknown
*/ public
static int CONST_UNKNOWN_ERROR
=
999;The
complete code for the interface can be found in JSBS_XML_Constants.
The
method for searching the XML-structure is located within the class
JSBS_XML_DisplayStrings
: package
js_base.xml;import
java.util.*;import
javax.swing.*;import
org.jdom.*;import
js_base.structures.JSBS_UniversalParameter;/**
.
. . . . .
. . . . . ./*
*
Method to search the XML-structure for the Title-Text of the frame
*/ public
int processJFrame(JFrame parmJFrame)
{/*
* Variables:
*/
/*
Name of the class that is passed as parameter */ String
strSearchedFrameClassName =
parmJFrame.getClass().getName().trim();/*
Element for the <FrameIndividual> Division, element for one
<Frame>
* element for the <FrameClass>, String
with the name of the FrameClass
* element for the
<FrameTitle> and String with the content of it.
*/ Element
elementFrameIndividual; Element
elementFrame; Element
elementFrameClass; String
strFrameClassName;
Element
elementFrameTitle;/*
List of all <Frame>-elements, size and index for searching it.
*/
List
listFrame; int
intlistFrameSize; int
intlistFrameIndex = 0;/*
* General
check if there are child-elements named <FrameIndividual>
present. */ elementFrameIndividual
= XML_RootElement.getChild(„FrameIndividual“); if
(elementFrameIndividual
== null)
{
StatusCode
=
CONST_FRAMEINDIVIDUAL_DIVISION_NOT_PRESENT; return
StatusCode; }/*
* Get
the list of <Frame>-elements and the number of elements
within. */ listFrame
= elementFrameIndividual.getChildren(); intlistFrameSize
= listFrame.size(); if
(intlistFrameSize
==
0) {
StatusCode
=
CONST_FRAMCLASS_NOT_PRESENT; return
StatusCode; }/*
* Inspect
each element of the list to find the element
fitting
the Class-Name of the JFrame passed as parameter. */ for
(intlistFrameIndex
= 0; intlistFrameIndex < intlistFrameSize;
intlistFrameIndex++)
{
elementFrame =
(Element) listFrame.get(intListFrameIndex);/* Get
the element with the <FrameClass> to compare its content
elementFrameClass
= elementFrame.getChild(
* with the Class-Name of the passed
parameter. */„FrameClass“); if
(elementFrameClass
== strFrameClassName
= elementFrameClass.getTextTrim();null)
{
StatusCode
=
CONST_FRAMECLASS_NOT_PRESENT; return
StatusCode; }
if
(strFrameClassName.compareTo(strSearchedFrameClassName)
== 0) {/* Fitting
<Frame>-element found within the list; extract
property for <FrameTitle>
* and
transfer it to the Title-Bar of JFrame (passed as
parameter). */ elementFrameTitle
= elementFrame.getChild(„FrameTitle“); if
(elementFrameTitle
== null)
{
StatusCode
=
CONST_FRAMETITLE_NOT_PRESENT; return
StatusCode; }
parmJFrame.setTitle(elementFrameTitle.getTextTrim()); StatusCode
=
CONST_OK;
return
StatusCode;} }/*
* List
searched without finding a <Frame>-element with
fitting class-name;
* return
the error. */ StatusCode
=
CONST_FRAMECLASS_NOT_PRESENT;
return
StatusCode;}The
complete code for the class can be found in JSBS_XML_DisplayStrings.
That
the just coded methods are called, the have to be 'uncommented' in
the class JSBS_FrameServices
: /*
*
Wrapper-method to be called from classes derived from
JSBS_StartFrame */ public
static int processLanguageDependantElements(JSBS_StartFrame
parmfrmJSBS_StartFrame) { }/* Return-Code
to pass the status, that was reported by called methods, back
*/ int
intStatusCode
= 0;/* /* local
StatusCode for comparisons */ int
locintStatusCode = 0;
* Call
the method that sets the text into the TitleBar of the frame
*/ locintStatusCode
=
parmfrmJSBS_StartFrame.structJSBS_XML_DisplayStrings.processJFrame(;parmfrmJSBS_StartFrame)/* Check
if another Code than 0 (OK) was returned and keep it in that case
*/ /* if
(locintStatusCode
> 0) intStatusCode
= loc;intStatusCode
* Get
the 'ContentPane' and call the method that inspects it recursive
*/ Container
locContainer = parmfrmJSBS_StartFrame.getContentPane();
locintStatusCode
=
parmfrmJSBS_StartFrame.structJSBS_XML_DisplayStrings.processJFrame(;parmfrmJSBS_StartFrame)/* Check
if another Code than 0 (OK) was returned and keep it in that case
*/ if
(locintStatusCode
> 0) intStatusCode
= loc;intStatusCode
/*
* Return
the Status to the caller */
return
intStatusCode;
The
complete code for the class can be found in JSBS_FrameServices.
Run
the application to see a first resultTo
see the result of the just typed code, run the application again by
selecting
>Run>Run....
Select
'JS_ErrDB_CommandCenter' (in the left column under 'Java
Application') and click the button [ Run ].
The
application should look like this. Please obey that the text in the
title bar reflects the content of the file 'DisplayStrings.xml'.
Not
much to see ?
In the step a lot of invisible basic work was done
and the text in the title bar is the first visible result.
More
code with visible results will be developed in the next step - hang
on !.
Next
Step:As
the XML-structure with the language dependant strings are now in the
memory, we will develop a recursive method to set the text to the
elements of the GUI.
JS_FC01h
- Setting the properties of the GUI-elements - part 2.