|
Light-Weight
Version 4.50
Tutorial

Contents
Introduction to the Light-Weight Visual Components Library.
Is it difficult to use the library?
Architecture.
Lightweight library packaging.
Lightweight library deployment.
Deployment steps.
Lightweight properties file format.
Lightweight Component.
Abstraction.
Lightweight component.
Lightweight container.
Lightweight painting.
Lightweight view management.
Lightweight events conception.
Lightweight validation.
Lightweight static objects.
Lightweight scrolling.
Lightweight desktop.
Lightweight application and applet.
Lightweight windows.

Light-Weight Visual Components Library (LwVCL) is a pure Java alternative to
humble AWT-based GUI interfaces for wide ranges of platforms, including
J2SE, J2ME Personal Profile (Personal Java), J2ME MIDP and Microsoft .NET.
Designed as lightweight but built separately from AWT (not on top of
the java.awt library like Swing), the LwVCL is the good alternative to
highly performant, memory-efficient, flexible GUI solution for embedded,
stand-alone and applet applications.
The LwVCL can be used on wide range of Personal Java (J2ME) compatible devices,
including Sharp Zaurus, Compaq iPAQ and top models of mobile phones with the
same API as it is used in J2SE application; our library is the most efficient
way to develop highly scalable GUI applications from J2SE to any J2ME Personal
Profile (Personal Java) and J2ME MIDP applications.
The best way to demonstrate the library usage is a good sample. The
table below shows very simple examples that have been created using the
lightweight library (left column) components and Java AWT components
(right column).The sample allows user to add (by using the "Add" button)
content of a text field to the list.
| Lightweight sample code |
AWT Sample code |
package org.zaval.lw.samples;
import org.zaval.lw.*;
import org.zaval.lw.event.*;
public class LwVCLDemo
{
public static void main(String[] args)
{
LwFrame frame = new LwFrame();
LwContainer root = frame.getRoot();
root.setLwLayout(new LwBorderLayout());
LwButton button = new LwButton("Add");
final LwList list=new LwList();
final LwTextField text=new LwTextField ("Demo",10);
button.addActionListener(new LwActionListener() {
public void actionPerformed(Object src, Object data)
{
list.addItem(text.getText());
}
});
root.add(LwBorderLayout.NORTH, text);
root.add(LwBorderLayout.CENTER, list);
root.add(LwBorderLayout.SOUTH, button);
list.getViewMan(true).setBorder("br.sunken");
frame.setSize(200, 200);
frame.setVisible(true);
}
}
|
package org.zaval.lw.samples;
import java.awt.*;
import java.awt.event.*;
public class AwtDemo
{
public static void main(String[] args)
{
Frame frame = new Frame();
frame.setLayout (new BorderLayout());
final List list = new List();
final TextField text=new TextField("Demo",10);
Button button = new Button("Add");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
list.addItem(text.getText());
}
});
frame.add(BorderLayout.SOUTH, button);
frame.add(BorderLayout.CENTER, list);
frame.add(BorderLayout.NORTH, text);
frame.setSize(200, 200);
frame.setVisible(true);
}
}
|
| Lightweight demo application |
AWT demo application |
 |
 |
These two applications are practically the same, so there is no problem for Java AWT
programmers to use the Light-Weight Visual Components Library.
The core idea is to reject java.awt.Component inheritance. The
library provides LwComponent interface that is a base for all
components of the library, instead of java.awt.Component. The
library architecture is shown below.
The lightweight library has three levels:
- Level 0 (Native). This level provides UI native classes that are necessary for the
next level (adaptive level) to have graphics surface, GUI event sources, and other specific
classes. For example Java AWT library supplies java.awt.Graphics, java.awt.Image,
java.awt.Canvas classes.
- Level 1 (Adaptive). This level adapts native events to
appropriate lightweight events, provides possibility to work with graphical
context and has a set of native-specific methods that are necessary for
the library. LwDesktop adaptive class is responsible for native
events conversion process and it provides set of methods to work with a
graphical context. LwToolkit adaptive class provides set of
native-dependent methods. This level is very important to use the
library on other systems that have their own Java UI implementations
(for example portable devices). To adapt the library it is necessary to
re-implement the level classes. Pay attention, you shouldn't touch the lightweight
components set, it is left as is.
- Level 2 (Light Weight). This is a core level that
provides all classes and components that are necessary to develop your own components and
applications based on the lightweight library. This level is what you will face with
during development lightweight applications, applets and components.
The level
can be divided as follows:
- Lightweight components. This is a set of widespread GUI components
that are ready to be used. The list of the components is shown below:
| GUI Component |
Short Description |
| LwCanvas |
This component implements LwComponent interface and should
be used as a base for your own lightweight components development.
This is something like java.awt.Canvas component provided by Java AWT
library.
|
| LwPanel |
This component implements LwContainer interface and should
be used as a base for your own lightweight containers development.
This is something like java.awt.Panel component provided by Java
AWT library.
|
| LwLabel |
This component is used to show text messages (including
multiline text). |
| LwButton |
This is the button component that can use other
lightweight components as its caption.
|
| LwCheckbox |
This is checkbox component that can be used to show radio group, checkboxes elements
|
| LwBorderPanel |
This is border panel that can be used as decorative panel to have
other component as its title. The title can have one of the following
alignments: top, bottom, left, right, center.
|
| LwLink |
This is text link component. It is like a text html link. |
| LwImage |
This is image component that can be used to show images ("gif" and
"jpg"). |
| LwStButton |
This is a toolbar button component. |
| LwAList |
This is abstract list component. There are two implementations
provided by the library: component list and rendered items list.
See the components descriptions below.
|
| LwList |
This is list component that allows you to customize the list
items rendering. The list can work in combo box mode.
|
| LwCompList |
This is list component that uses other components as the list items.
The component applies different layouts (that implement special interface)
to navigate through its items. The list can work in combo box mode.
|
| LwTextField |
This is text field component that can be used to enter single-line text,
multi-line text, fixed size text and passwords. The component provides text
block operations.
|
| LwSplitPan |
This is splitter panel component that can be used to split two components
and place the components inside sizeable areas. The splitter can have
horizontal or vertical alignment.
|
| LwNotebook |
This is notebook component that supports different alignments for notebook
tabs (top, bottom, left and right) and allows the tab rendering customization.
|
| LwScrollPan |
This is scroll panel component that can be used to organize scrolling for
any lightweight component. |
| LwScroll |
This is scroll bar component that can have horizontal or vertical orientation. |
| LwTree |
This is tree view component that can be used to render and navigate
through tree-like structures. The component provides ability to customize tree
items views and allows the tree items customizable editing. |
| LwStatusBar |
This is status bar component that can be used to organize status bar panel. |
| LwProgress |
This is progress bar component that can be used to show progress status for different actions.
|
| LwGrid |
This is powerful grid component to render and edit a matrix data model items.
The component is fully customizable. You can provide your own grid cells editing
and painting mechanism.
|
| LwLine |
This is simple component that can be used as the line separator for the popup menu
components. The component renders vertical or horizontal line using different styles.
|
| LwMenu |
This is popup menu component that uses other components as its items.
|
| LwMenuBar |
This is menu bar component that can be placed in any part of your application
form. It is possible to use a custom layout manager to lay out the menu bar items.
|
| LwVCL extensions (lwext.jar) |
| LwTreeGrid |
This is tree grid component that is based on LwGrid component and is used to render
two bound data models: tree data model and matrix data model.
|
| LwSpin |
This is spin component allows you to input bound integer value. |
| LwMaskTextField |
This is text field mask component that allows filtering input data according
to a specified mask. It is possible to use letter, numeric and date masks.
Alternatively, you can implement your own mask handlers. |
| LwWindow |
This is internal frame window implementation. |
| LwSlider |
This is slider component that can be used to get integer value for the
specified interval (like using ruler to measure distance).
|
| LwColorPanel |
This is special panel that provides a user interface to select a color value.
|
| LwFontPanel |
This is special panel that provides a user interface to select font characteristics.
|
| LwFilePanel |
This is special panel that provides a user interface to select a file.
|
| LwBlankDialog |
This is component that allows constructing a dialog using a specified content.
For example, LwColorPanel, LwFontPanel, LwFilePanel panels can be used as the
dialog content.
|
| LwExtender |
This is component that allows you to show/hide the specified embedded
component.
|
-
Lightweight managers. The managers play key role to make the library living.
Events delivering strategy, painting algorithm, focus management and many other
things are controlled by the lightweight managers. The library allows you to
create new one or customize old manager implementations. The manager deployment
concept is powerful but still easy to use (see chapter -
"Lightweight library deployment").
Below you can find brief description for a set of managers that are implemented and
used within the library.
| Lightweight Manager |
Short Description |
| LwEventManager |
This is one of the core managers - it connects levels 1 and 2. The main purpose of
this manager is to determine event delivery strategy. Every lightweight event goes
to the manager and only manager can distribute event according event distribution
strategy. Lightweight events can be generated by lightweight components, lightweight
managers or Level 1. This manager supports listeners that can be used with other
lightweight managers or components.
|
LwPaintManager (LwPaintManImpl) |
Paint manager is responsible for actual presentation of the lightweight components (painting).
Initial manager implementation uses double buffering to speed up lightweight components painting.
It also supports component transparency and views.
|
| LwFocusManager |
The manager controls focus for components that can be used as input elements (buttons, text
fields and so on). The lightweight component has canHaveFocus method to define if it can have
focus. This manager is registered as a mouse and keyboard listener. To "jump" through
components you can use a mouse button (mouse down event) or "TAB" key.
|
| LwCursorManager |
The manager controls mouse cursor status. LwComponent interface does not control mouse
cursor itself, so you should use the cursor manager to customize the mouse cursor view.
|
| LwClipboardMan |
The manager is used to store and fetch data from the clipboard. The core clipboard
implementation does not support interaction with the system clipboard, so it is impossible
to exchange data between other applications and the lightweight components. However, you
can use AWTClipboardMan manager provided by the extension package of the library to
have the ability.
|
| LwPopupManager |
This manager should be used to set a lightweight popup menu for a component. The library
doesn't use the Java AWT popup menu implementation and has not any relations with the Java
AWT popup menu components. The old LwVCL versions provide the special popup manager -
AWTPopupManager - that implements popup menu basing on Java AWT library. The manager
has been removed and it is not supported for the latest LwVCL versions.
|
| AWTClipboardMan |
This is clipboard manager implementation that is based on java.awt.datatransfer.Clipboard
Java AWT class. Use the manager if you want to work with the system clipboard.
|
| LwTooltipMan |
This is tool tips manager that provides ability to specify tool-tips for lightweight
components. Any lightweight component can be used as the tool-tip.
|
| J2SEPaintManImp |
This is advanced paint manager implementation that uses Java 1.4+ VolatileImage
class to speed up painting performance. The idea is to use Video Adapter Memory to
store back buffer data. Pay attention the class is not included in any LwVCL package.
It is up to you to compile it and put in a right place.
|
Just to summarize: the LwVCL has 3-Tier architecture that divides functionality into three
independent levels. As result the lightweight components set is abstract and can be adapted
for other platforms and systems (different JVMs for portable devices, for example) according
to your needs. The library is flexible. For example, you can easily modify the event distributing
mechanism, the painting algorithm and so on. Provided components set is rich (about 30 UI components)
and contains various (simple and complex) components.
The library provides the following artefacts:
- The core package - lw.jar.
The package contains basic set of lightweight components, the core classes and interfaces
that are functional part of the library. The basic components set includes not only simple
and trivial components. The LwTree, LwGrid, LwNotebook and others are supplied with
the core package. The core package is minimal what you need to work with the library.
- The extension package - lwext.jar. The package contains additional
lightweight components like masked input components, tree grid component and so on.
- Themes package - lw-theme.jar. The package contains additional themes
(look and feels). You should add the package into your classpath if you want to use
a LwVCL theme.
- The GUI designer package (GDP) - lw-gdp.jar. The package contains some
lightweight components that relate to component manipulation abilities.
The library packaging rules are the following:
| org.zaval.util.* |
contains the utilities classes and interfaces.
|
| org.zaval.misc.* |
contains the different unclassified classes and interfaces.
|
| org.zaval.data.* |
contains the data models related classes and interfaces.
|
| org.zaval.lw.* |
contains LwVCL components related stuff: UI components, UI events, event
managers, theme classes, views, renders, etc.
|
| org.zaval.lw.theme.* |
contains LwVCL themes classes, images, properties files. Any available theme has
to be developed as a sub-package. For example, LwVCL default theme resources
are placed in org.zaval.lw.theme.base package.
|
| org.zaval.lw.theme.base.* |
contains the basic theme resources - images and properties files. The basic theme is used as a
default by the library.
|
| org.zaval.lw.demo.* |
contains LwVCL demos applications and applets.
|
| org.zaval.lw.samples.* |
contains LwVCL sample applications and applets. Consider any sample as the small
application that illustrates a LwVCL feature, a component usage. It is supposed to have
a sample application developed according to the following rules:
If a sample is complied with the rules described above, it can be included in the
sample central application. The application provides ability to have and to see
all available samples in one place.
|
The event and listener classes and interfaces should be stored in related sub-package
called "event". For example all UI components event and listener classes are put in
the "org.zaval.lw.event" package. It is recommended to keep the declared structure
for any new developed LwVCL parts.
A lot of different information LwVCL stores in the properties files. Mainly the
properties describe various static objects that should be created during
initialization phase. The components use the static object to customize its
views, have default colors, fonts, layouts and so on. The library uses a theme
package as the base directory where the properties files are supposed to be stored.
By default LwVCL uses the basic theme. The theme is placed in "org.zaval.lw.theme.base"
package. For any theme the following properties files should exist:
- lw.propertiesThe file is used by the core (lw.jar) and specifies properties
set that is necessary for the LwVCL core components. The name of the properties file
is hard-coded and cannot be changed.
- lwext.propertiesThe file is used by the extension package (lwext.jar) and
specifies properties that is necessary for the LwVCL extension components. The name
of the properties file is hard-coded and cannot be changed.
- colors.propertiesThis file contains specific data for LwColorPanel component
(this is extension package component).
Any other LwVCL theme has to provide the same properties stuff. For example,
the new pseudo 3D theme (see the org.zaval.lw.theme.p3d package) provides
own "lw.properties", "lwext.properties" and "colors.properties" files. You can
specify the base directory by the environment variable (or by the appropriate
parameter of an applet) that called "lwvcl.base". Pay attention, the value is
"org.zaval.lw" package related in a case if it doesn't start from "/" character.
For example, to use the pseudo 3D theme for your application use the following
command:
java -Dlwvcl.base=theme/p3d
Let's consider your new developed theme is stored outside of "org.zaval.lw" package,
somewhere in "my.theme.win" package. In this case the command should be as follow:
java -Dlwvcl.base=/my/theme/win
This chapter describes the deployment (LwVCL initialization) process in more details.
The main actor of the deployment process is LwToolkit class. This class has startVCL
static method that starts the deployment process. The method should be executed before
any lightweight component usage (in most cases it is not necessary to call the method
manually. This is LwFrame or LwApplet class who does it automatically).
The following actions are performed during the deployment phase:
-
Reads the "lwvcl.base" property value to understand what the source directory is. The
source directory should contain all necessary properties files and resources (images,
classes and so on).
-
If the "lwvcl.base" property is not specified LwVCL uses "org/zaval/lw/theme/base" as
the base directory.
-
Reads the "lw.properties" file. The file contains descriptions for all event managers,
static objects (views, fonts, colors and so on) that have to instantiated. LwVCL reads
the file line by line starting from the first line. There are several rules you should
know:
-
The property name is used as the key of the created instance. The key has to be used
to request the static object. Be attention, assigning the static object key.
-
For the following managers its key names are fixed:
- Paint manager is specified by the "paint" property.
- Event manager is specified by the "event" property.
- Focus manager is specified by the "focus" property.
- Tool tip manager is specified by the "tooltip" property.
- Clipboard manager is specified by the "clip" property.
- Popup manager is specified by the "pop" property.
- The event and paint managers are mandatory and should be specified ahead of any
others static objects.
- There is one more special fixed property name - "lw.wiz". The property is mandatory
and it specifies LwWizard class name that will be used to created object
which customizes LwVCL components. The wizard is called just after a lightweight
component has been instantiated.
- The class names specified in a properties file are related to "org.zaval.lw" package.
It means if you don't specify a package name for your class LwVCL will consider the
class packaged in "org.zaval.lw".
-
Parses the properties file, creates and registers described static objects. Static object is
an object whose functionality can be shared safely with other objects. It means that it is
not necessary to have several instances for such objects, it is possible to create one instance
and other objects can use it. The static object concept helps the library to decrease system
resource usage and increase its performance. Take in account the following notions concerning
the properties file parsing:
- The library identifies event manager objects by testing if the class implements LwManager
interface.
- An event manager is registered as a global event listener (it means the manager will listen
events generated by all lightweight components) if it implements corresponding listener
interface, so you don't need to register or un-register your managers as the listener
manually, this will be done by the LwToolkit class automatically.
- Use the getStaticObj(Object key) method of the LwToolkit class to fetch
a static object.
- Use the getStaticObj(Object key, boolean b) method of the LwToolkit class to fetch
a static object cloned instance.
- If the LwVCL extension package is used, the same procedure is repeated for the
"lwext.properties" properties file.
As we mentioned the lightweight properties file names are hard-coded ("lw.properties"
for core and "lwext.properties" for extension package). Both of them have the same format
- it consists of name-value pairs:
<propertyName>=<value>
The default resource directory is "org/zaval/lw/theme/base". This directory is called "base"
directory. All LwVCL resources, properties files and the like are loaded related to this
base directory (see, for example the getImage, getProperties methods of the LwToolkit class).
It is possible to configure the base directory by the special property called "lwvcl.base"
as follows:
Let's determine the properties file format more precisely. Property name has nothing special it
is just a string that will be used to identify the described static object. The value is
more complex:
value=(ClassName | Descriptor):[argument[,argument]*]
So as you can see the value consists of two parts:
- First part is mandatory and it specifies a class name that should be instantiate.
Instead of the class name you can use a descriptor. Actually, descriptor is more
easy way to specify some types of the static object. The table below shows what
descriptor types are supported by the library:
|
Descriptor
|
Interpretation
|
| "string" |
This is simplified format for the string. In this case it is not necessary to
specify a class name - java.lang.String. You can specify a string as the property
value directly using double quotes. For example:
propertyName="My String"
|
| %num1,num2,num3 |
This is simplified format to specify a RGB colors. In this case it is not necessary to
specify a class name - java.awt.Color. You can specify a color as the property value
using the '%' character as a prefix. For example:
white.color=%255,255,255
|
| &fontName,fontStyle,fontSize |
This is simplified format to specify a font. In this case it is not necessary to
specify a class name - java.awt.Font. You can specify a font as the property
value using the '&' character as a prefix. For example:
my.font=&Serif,0,12
|
| >width,height |
This is simplified format to specify a size. In this case it is not necessary
to specify a class name - java.awt.Dimension. You can specify a size as
the property value using the '>' character as a prefix. For example:
my.size=>200,300
|
- The second part follows just after the object class specification is arguments list.
The section is optional and contains list of arguments separated by comma which are
used as the input for the specified class constructor. An argument can have one of
the following types:
|
Type
|
Description
|
| Integer |
An integer argument is an integer value (without quotes). For example:
br.plain=LwBorder:1
|
| String |
A string argument should be quoted. For example, to create java.io.File
class instance for the "test.exe" file it is necessary to add the following
property:
file=java.io.File:"test.exe"
|
| Boolean |
The boolean argument can be either true or false (without quotes). For example:
border.arg=true
|
| Reference |
The argument type is reference (by a key) to another static object. For example,
we can specify a path to a file as a string object and use a reference to the object
to instantiate the java.io.File object:
filename="c:/bin/test/start.exe"
file=java.io.File:@filename
|
If the arguments list has not been specified than the LwToolkit class will try to
use default constructor to create the static object instance.
Let's consider the abstraction component (GUI) definition. Actually
there are three core notions (see image below):
- View. View is like "face". View is used to reflect the
component state and it allows users interacting with a component.
- Validation. Validation is bound with different metrical
parameters (preferred size, fonts, and so on). These parameters are used
to render and layout the component. A GUI component can be shown if it
is valid.
- Events. Events are like "blood" that makes the GUI component
"alive". A GUI component can receive, handle and perform different
events.
As rule these three notions depend on each other, the image above shows
these dependences by intersection three notion-circles. The concept is
simple, but it helps to understand library ideas correctly.
Lightweight component is a component that implements LwComponent interface.
Draw attention that lightweight component has no relations with java.awt.Component
(like AWT or SWING components) class. So the lightweight component rejects any
relationships with the "native" java.awt.Component class. This approach helps to
solve the following problems:
-
Hard-coded view. It is impossible to inherit, for example, java.awt.TextField
component to re-implement some functionality, because it is not a lightweight
component. Actually the component is a wrapper for a system GUI component and
you cannot control its behavior.
-
Improve painting and component creating performance. Try to use a large number
of Java AWT components in a real project. An application will work extremely
slowly (actually, it is impossible to use big number of Java AWT components).
-
The Java AWT UI components set is not enough for applications and applets development.
The SWING library is more powerful than Java AWT library, but it's very
greedy to the system resources (have a look to the memory usage).
Moreover, SWING components are based on AWT components
(java.awt.Component). The big size of the library makes it useless
for mobile devices and thin clients (the client has to download the whole
package, or install special plug-in to his browser).
In addition, the library provides lightweight container interface -
LwContainer. Usage of the simplest implementation of this interface
(LwPanel) is practically identical to java.awt.Container usage.
Before we go to the description of the
lightweight component let's define base lightweight notions:
Det. 1: Validation - a lightweight component is valid if all metrical
characteristics are defined and calculated. For example, if a text is changed for
LwLabel component than it is necessary to recalculate size of the new text.
The new size will be used to calculate preferred size of the component.
Det. 2: Transparency - a lightweight component is transparent if painting
process doesn't use a background of the component to fill its surface. In this case
the component uses a parent background.
Det. 3: Preferred size - this is size that a lightweight component "wants" to
have plus the component insets. Preferred size depends on validation status, only a
valid component can have correct preferred size.
Det. 4: Clip Area - this area where painting is possible. Rendering
operations have no effect outside of the clipping area.
Det. 5: Insets - this right, left, top, bottom indents that determine
clip area for painting process. If a component has size - (w, h), location - (x, y)
and insets - (left, right, top, bottom) than it will have the following clip area:
(x + left, y + top, w - left - right, h - top - bottom). Moreover layout managers use
the insets as the gaps to layout its child components.
Det. 6: Origin - this is a component view offset. Origin defines how the
component view has to be offset relatively the component point zero-zero
(basis of coordinate system). This is useful to organize scrolling.
Det. 7: Enablement - enablement determines ability to receive, handle and
perform events for a component. Only enabled component can be a member of event
distribution process.
Below you can find basic properties of the lightweight components:
| Property name |
Methods |
Description |
| size |
Dimension
getSize() setSize(int, int) |
This property determines size of the component. If component is a child
of a container that layouts children according to preferred size than
it is impossible to determine size of the component via method setSize(int, int)
(see chapter Lightweight container to understand the
layout algorithm)
|
| location |
Point
getLocation() setLocation(int, int) |
This property determines location of the component inside a container.
The parent container can set the location for their children by a
layout manager. So often the set location will not have effect
|
| preferred
size |
Dimension
getPreferredSize() setPSSize(int, int) |
This property defines a preferred size of a component. There are two possible
ways to set the preferred size:
-
1. The preferred size is calculated according to metrical
characteristics (LwComponent) or according to a layout
manager implementation (LwContainer).
-
2. The preferred size can be fixed by setPSSize(int,
int) method usage.
|
| opaque |
boolean
isOpaque() setOpaque(boolean) |
This property is responsible for component transparency. If it is set
to "false" the component is transparent.
|
| visibility |
boolean
isVisible() setVisible(boolean) |
This property defines visibility state of the component. If it is set to "true"
the paint manager will render the component and a parent container will layout one.
|
| enable |
boolean
isEnabled() setEnabled(boolean) |
This property defines whether component will receive events from other
components. If it is set to "true" the component will participate in the event
distribution process.
|
| validation |
boolean
isValid() validate() |
This property defines validation status of the component.
If it is set to "true" the component is valid. To perform
validation process use the validate() method. A container component
is responsible for validation status of its child components.
|
| insets |
Insets
getInsets() setInsets(top, left, bottom,
right) |
This property defines the insets for a component. |
| origin |
Point getOrigin() |
This property defines an origin for a component. |
| background |
Color
getBackground() setBackground(Color) |
This property defines a background color that will be used
by the component to fill its area (if the component is not
transparent)
|
Lightweight container is a lightweight component that can have other components as child.
The library provides container interface - LwContainer and of course, has generic
implementation of this interface - LwPanel. Lightweight container usage is similar
to java.awt.Container usage, but there are two essential differences:
-
A layout manager has to be always defined for the lightweight container. AWT library
allows going even without layout manager usage, but you can face with problems trying
to combine layout and non-layout ways in an AWT application. However, it does not mean
that it is impossible to layout lightweight components using sizes and locations
specified by the setSize(int, int) and setLocation(int, int) methods. The library
provides special layout manager - LwRasterLayout - for this purpose. The complete
set of layouts that go with the library is shown below:
| Layout |
Short Description |
| LwBorderLayout |
This is analog of java.awt.BorderLayout. |
| LwGridLayout |
This is like a mix of java.awt.GridLayout and
java.awt.GridBagLayout layouts |
| LwRasterLayout |
This layout manager uses location and size that have been set by the
setLocation(int, int) and setSize(int, int) methods or the layout
uses preferred sizes of the child components. The special boolean flag
(that is passed as argument during initialization of the layout) points
what size (preferred of set by the setSize(int, int) method) should be applied
for the child components.
|
| LwFlowLayout |
This is like a java.awt.LwFlowLayout but it has the
additional features. |
| LwListLayout |
This is a special layout that is used by the LwList component.
|
| LwPercentLayout |
This layout manager places child components vertically or horizontally
according to its percentage constraints.
|
-
The next difference is that lightweight layout manager is designed to layout
Layoutable components inside LayoutContainer. It means that lightweight layout
managers can be used for other components (even non-GUI components) that implement
two interfaces (Layoutable and LayoutContainer), not only for lightweight components.
At the same time Java AWT layout managers cannot be reused outside Java AWT Library.
Any lightweight component has a view. There are two ways to define a
lightweight component view:
- Lightweight component provides two methods that can be overridden:
paint(Graphics g) and update(Graphics g). First method is
used to paint a view of the component and the second method for updating
the component area (filling with the background color). This is the same the Java
AWT painting component concept.
- Lightweight component has a view manager. The manager can be used to
determine view for the component dynamically. The library provides a set
of ready to use views (border, image, text, etc).
These two ways are demonstrated in the table below:
| Painting methods
overriding |
View manager
usage |
public class MyComponent
extends LwCanvas
{
public update (Graphics g)
{
Dimension size = getSize();
g.setColor(Color.red);
g.fillRect(0, 0, size.width, size.height);
}
public paint (Graphics g) {
g.setColor(Color.black);
g.drawString("This is my view", 20, 20);
}
}
|
LwComponent c = new LwCanvas ();
LwViewMan m = c.getViewMan(true);
// Set the component border view
m.setBorder(new LwBorder(LwBorder.PLAIN));
// Set the image as the component background
m.setBg(new LwImgRenderer("myBg.gif")) ;
// Set the "face" render to paint the text
m.setView(new LwTextRenderer("This is my view"));
|
Lightweight component provides the repaint method. This method initiates repainting process.
Lightweight component has no specific implementation for this method - it just calls
appropriate method of the lightweight paint manager that knows how the components should be painted.
Current implementation of the paint manager supports the following features:
- Double buffering.
It means that lightweight components are painted using off-screen memory buffer and after that the
buffer is painted on an application surface. This feature allows avoiding blinking
and improves painting performance. The double buffering feature can be toggled off with
the special method of the paint manager if you need system resources saving.
- Component transparency.
Any lightweight component can be transparent. It means that the component has no background.
In this case a parent component background will be used as the child background.
- View manager support.
View manager is a special class that determines "face" of the component by a set of views.
View is a class that provides painting rules. This feature allows using view for any
lightweight component with no changes to the component functionality. To get more information
about view management and view creation see chapter Lightweight View Manager.
The current lightweight paint manager implementation uses the following algorithm to
draw a component:
- Validates a component if it is necessary.
-
Calls update(Graphics) method if the component is not transparent (a component is
transparent if the isOpaque method returns "false"). If the component is not transparent
and has a view manager which defines a background view than the view will be used
as the component background (in this case the update(Graphics) method is not called),
if the component has no background view than the background color will be used
to fill the component area.
-
If the component has a view manager that specifies a border
view than the view will be rendered.
-
Calculates a clip area. The clip area is calculated as intersection of
the component size (without the component insets) and the current clip bounds.
-
If the component determines its own origin via the getOrigin() method than
the paint manager sets new origin. The origin can be used if it is necessary to
shift the component image (for example, this feature is used to organize
scrolling for LwTextField component).
-
If the component has a view manager and the view manager determines a "face" view
than the paint manager draws the view.
-
Calls the paint(Graphics) method of the component
If the component is a container and has a child components than the paint manager
computes clip area, transforms point of origin accordingly the child location and
performs painting process for the child as described above. The process is repeated
for all visible child components. At the end the paintOnTop(Graphics) method
is called.
First of all let's understand what the view is. Often you face with the following two tasks:
-
Decorative elements rendering. In real applications every GUI component uses some decorative
elements as a part of its "face". For example, a checkbox component has a toggle element.
Any UI components can have a border or a complex background (for example, image).
It is necessary to have possibility to control the components elements' views
(for example, somebody can want to use a custom view for a checkbox toggle element).
Java AWT library components do not provide the possibility - to change its elements'
views dynamically, as the Java AWT components views are hard-coded with the paint(Graphics)
method. In this case, if you want to change a component view, it is necessary to inherit
the component and override the paint(Graphics) method. The library provides special abstract
class - LwView to implement your own views. The views can be used as a part of a component
"face" by using the component view manager.
-
Data model rendering. The library provides the special abstract class - LwRender.
The class inherits the LwView class. The main difference is the render is bound
with an object (it is called data model or target object). The render "knows"
how the target object should be rendered. For example, there is the image render provided
by the library can render an image (target object).
The second question is views and renders usage. For this purpose lightweight components
provide a view manager. The manager provides ability to determine three view types
- border view - the view is used to paint a component border
-
background view - the view is used to paint a background (for example, it is possible
to use an image as a component background by the LwImgRender render usage)
- face view - the view is used as a face of the component (for example, the
LwLabel component uses the LwTextRender render as the face view)
The library provides advance view manager that can be used to support dynamic view
changing. The main feature is the manger can contain set of named views for a component
face. The name of the face that should be rendered in the certain time is determined
according to the component needs (states).
For example, the LwButton component uses the advanced manager to define two named views:
"button.on" and "button.off". In this case, the "button.on" face corresponds to button
pressed state and the "button.off" corresponds to button un-pressed state. The button
component uses an appropriate view depending on its state.
The last question is a view painting process. To define your own view it is necessary to inherit
the LwView or LwRender class and determine paint method for the class. The method is
called with a paint manager. The paint manager passes a graphics context, a location - where the
view has to be drawn, a size - that has to be used and an instance of the object for which the
view is painted. The view can be painted with one of the three manners depending on the view
type:
-
ORIGINAL type. In this case, the paint manager passes preferred size of the view as
the view size and insets.left, insets.top as the view location.
-
STRETCH type. In this case, the paint manager passes size of an owner component
for which the view is drawn, location is (0, 0). The type is used to stretch the view
image along the owner component area.
-
MOSAIC type. In this case, the paint manager passes preferred size of the view
as the view size and the view will be painted as many times as it can be placed inside
the component area, the view location will be calculated for every time. The type is
useful if it is necessary to define background pattern (for example using image pattern)
for a component background.
The table below shows views and renders that go within this library:
| View/Render |
Short Description |
| LwBorder |
This view provides set of different borders that can be used as border view for a component.
The view is used to define a component border. It is not necessary to create the border
view instances, because the library stores the border set as a set of static objects
that are available (use the LwToolkit class) by following keys:
"br.etched", "br.raised", "br.sunken", "br.plain", "br.dot".
|
| LwTitledBorder |
This view functionality is based on the LwBorder view and it can be used to paint a
border element with a title area.
|
| LwImgRender |
This render is used to paint an image or the specified part of the target image
(the target object has java.awt.Image type).
|
| LwTextRender |
This render is used to paint a text (target object has org.zaval.data.Text type).
The render supports the selected text painting.
|
| LwPasswordText |
This render is used to paint a password text and is based on the LwTextRender render.
|
| LwCompRender |
This render is used to paint a lightweight component (the target object has
org.zaval.lw.LwComponent type).
|
| LwWrappedText |
This render is used to paint a wrapped text. The render splits a text
to the several lines in a case if the line cannot be placed inside
the area wholly.
|
This is a very important chapter. The LwVCL library uses listener concept like Java AWT
or SWING libraries. It means that if you want to handle any event you should register an
appropriate event listener. The events and listeners are much like in AWT library
(see package org.zaval.lw.event.*) and hope, you'll get it easily. But there are several
key differences:
-
First of all, lightweight components don't provide listener support. The lightweight
component doesn't implement event distribution functionality and this is really good,
because event distribution is concentrated in one place - event manager. This way has
one more advantage: it decreases memory usage because lightweight components should not
contain the list of listeners (listeners support). It's very simple: if you want to
catch events inside your lightweight component, it is necessary just to implement an
appropriate listener interface and the library event manager will immediately start
sending the events to the component. For example, to catch mouse events inside your
component, you should implement LwMouseListener listener interface. As it was described
above, a lightweight component doesn't provide listeners support for mouse, key,
component, container, focus and other events unlike a Java AWT component. But it is
possible to handle all these events using LwEventManager event manager, by registering
an appropriate listener. In this case the registered listener will get the events for
all components, so if you want to listen the events for the certain lightweight
component you should test a source of the events.
-
The lightweight library provides the mechanism to control input child events. The input
event is an event that is initiated by mouse, keyboard or any other input device. This
is very important to have this feature for creating composite components. Composite
component is a container that consists of several components (child components) that
have to work together. For example the LwButton component is a composite component. The button
component can have other components (including composite components) as its child.
The problem, in this case, is following: if a mouse button has been clicked over any
child component, the button mouse listener will not get the mouse event and so cannot
handle it. There are several ways to resolve the problem:
-
Register a mouse listener in by the event manager and test if the source object is
the button component or its child component. This solution is like Java AWT (but in
this case it is necessary to test if the event source of the event is the child of the
composite component), but this way doesn't solve the problem if you want to use other
composite component as the button container child component (you cannot
control a composite child component).
-
Control child components' events. The Java AWT hasn't anything like that. The main
idea is the parent component can control input events distributing process for its
child components. In this case the parent should implement the LwComposite interface
and starting from the moment the event manager will "ask" the composite component
if the child component input event should be re-directed to the parent. If the
composite component says to redirect the input event, the lightweight event manager
distributes the event as if the child component doesn't exist. The child becomes
"transparent" for the input event. The image below illustrates the composite
components concept:
-
First, the LwDesktop (this is lightweight top-level container) component gets a native
input event (mouse event) and converts the event to an appropriate lightweight event.
-
The LwDesktop component asks the LwEventManager manager what lightweight component is
a source of the originated event.
-
The LwEventManager manager defines the source according to the mouse
cursor location.
-
The LwEventManager manager looks for a parent composite component
-
If the parent composite component exists than the LwEventManager manager
asks it (by executing the catchInput method of the composite component)
whether the child input event should be re-directed to the composite
component.
-
The LwEventManager class distributes the input event to the composite
component or the child component depending on the previous step result.
The algorithm is recursive, so it will work fine if there are several
composite components in a hierarchy.
The validation is also important part of a lightweight component lifecycle.
In compliance with validation notion only a valid component can be laid out
and painted. The main purpose of the validation process is to calculate the
component metrics. The metrics define a preferred size and the preferred
size is used to layout the child components by applying a layout manager
of the parent container. The library provides two types of lightweight
components and accordingly, there are two ways to calculate component
metrics:
-
LwComponent (LwCanvas), LwView, LwRender. These interfaces determine
simple lightweight component and views. In this case validation process
calls the recalc() method to compute component and view metrics. To
perform a validation process you should not call the method directly,
it is necessary to call the validate() method of the lightweight component
or view and after that, if the component is not valid the recalc()
method is executed. It means that the recalc() method will be executed
only if it is necessary. It allows avoiding redundant calculation of
the component metrics.
-
LwContainer (LwPanel), LwViewMan. These interfaces and classes determine components and
views containers. The main differences are the following:
-
As rule, this is the container layout manager who defines the component
metrics (preferred size).
-
The container is responsible for the child components validation and
allocation (by using the given layout manager).
The container is valid if its metrics (preferred size) are calculated, child components
are validated and laid out. You should override the recalc() method to perform the metrics
calculation inside the method. Draw attention that the container is responsible
for its child components validation. It means, if the validation process is performed
for the container by executing the validate() method, it starts validation of the child
components.
The library has the special object type - static. The static object is a class whose
instance can be used safely by the other classes. For example, the lightweight component
view manager has a method to define border view, but there are only several types of the
borders and it is not necessary to create the same border view instances for different
components. In this case, we can have a set of border view instances and share its
between lightweight components. The static object concept is used to decrease
the system resources usage and improve the library performance.
Let's define the notion of the static object, what class can be used as the static?
It is obvious, that a static class instance should not allow any properties changes,
because the same instance is shared between several classes. The static object has
to comply with following statements:
-
Any properties changes for a static object instance are not allowed.
All properties values should be defined during the instance construction.
-
To use a static object instance it is necessary to describe the static
object in the lightweight properties file (static object section). And only
after that the instance will be available by the getStaticObj method of
the LwToolkit class.
-
It is possible to use integer, string or boolean types as a static
object constructor arguments.
-
The library identifies an instance of the static object by the
instance key (to get the instance it is necessary to know the key).
The key is defined in the corresponding section of the lightweight
properties file.
There are two ways to organize scrolling for a GUI component:
- By changing the component location inside the parent container.
- By moving the component view.
The LwVCL library supports both ways. The basic rules that you should
follow to implement a component scrolling are shown below:
-
Use the org.zaval.misc.ScrollObj interface to provide an appropriate
scrolling mechanism, the scrolling object size and its current location.
The information provided by the interface is used with the scroll panel
component (LwScrollPan).
-
Use the getOrigin method of the LwComponent interface if it is
necessary to move a view for the component. The method tells the library
(paint manager uses the information) how the component view should be moved
relatively to the component origin.
-
Use the getLayoutOffset method if it is necessary to scroll the child
components inside the parent container. The method points a layout manager how
the child components should be shifted.
-
The basic idea is all lightweight components "live" on the LwDesktop component. This is the root
container for others. The desktop is lightweight container that consists of layers
(desktop child components) where every layer is special lightweight container (LwLayer)
placed over all desktop area. Whenever any lightweight event is performed the desktop
looks for a layer that is active and only this layer's components have a chance to get and handle the event.
In other words the desktop is like sandwiched pie where only one layer can be active
in the given moment. Pay attention that several layers can want to be active, in this
case the desktop selects last added layer.
As it has been mentioned before, layer is a special lightweight container. The layers get
the following events from the desktop:
- Mouse pressed event.
- Key pressed event.
A layer gets the event before any events distribution.
The purpose is to give a chance for the layers to be activated. For example, the window
layer uses the mouse pressed event to activate a window.
The active layer additionally gets the focus setup and focus release events (the events are
performed when the desktop got or lost the focus). The other important thing
that is defined by the layer is the focus root component. The root component is used
with the focus manager as the top-level component to look up next focus owner
(whenever "TAB" key is pressed).
The current LwVCL desktop implementation provides the following two layers:
-
Root layer (has "root" ID). This and only this layer should be used to add any
child component on the desktop area.
-
Window layer (has "win" ID). This layer should be used to open, close, activate
LwVCL internal windows.
To work with the layers the LwDesktop container provides set of methods. The desktop
is the lightweight container, so you can use container API to insert, remove your
own layers implementations.
This chapter describes lightweight application components. The desktop is the base
for any lightweight application. The desktop provides set of layers where all other
lightweight components can be resided. As it has been described in the previous chapter
the desktop provides two layers that are ready to use:
-
Root layer. Use the getRootLayer() desktop method to get the layer.
The layer should be used to add any child components to the desktop.
-
Window layer. Use the getLayer("win") desktop method to get the layer.
The layer provides ability to open, close, activate internal window components.
It is possible to use any lightweight component as the window. For example,
combo box component shows popup pad as the lightweight internal window.
Moreover the library provides the LwWindow component that is much like
"classical" window. Draw attention that any desktop window cannot be
rendered outside the desktop area.
To create a standalone application you can use the LwFrame class. This is not a
lightweight component, actually this is an extension of the java.awt.Frame
class where the lightweight desktop is resided. To get the desktop root layer use
getRoot() method of the LwFrame class. The sample below illustrates
this class usage:
…
LwFrame frame = new LwFrame();
frame.setSize(400, 400);
LwContainer root = frame.getRoot();
root.add(new LwButton("Button 1"));
…
frame.setVisible (true);
…
The library provides LwApplet class that is like LwFrame and should be used for
lightweight applet creation as follow:
public class MyApplet
extends java.applet.Applet
{
public void init ()
{
super.init();
LwContainer root = getRoot();
root.add (new LwButton("Button 1"));
…
}
…
}
…
The LwVCL library supports internal windows by providing the window layer. The list below
illustrates the basic notions of the window concept:
-
There is not a special component that implements the lightweight window
(except the LwWindow and LwBlankDialog components), since any lightweight
component can be used as the window.
-
A lightweight window can be opened, closed, activated or deactivated
using the window layer (see the LwWinLayer class). The layer can be got by
the getLayer(…) method of the desktop. Use "win" value as the layer ID.
-
A lightweight window is placed inside desktop area and it is impossible
to show the window outside this area.
-
A modal window is activated immediately as it is opened.
-
A modal window doesn't allow activation of the windows that have been opened before it.
-
Focus can be shifted between the active window components by pressing the "TAB" key.
-
The active window is a destination for all originated events; it means that other
none-active windows won't get any events.
The image below shows state transitions of a particular window between consecutive opening and
closing. When a window changes its state, listeners are notified on the event corresponding to
state window transits to.
The library provides ability to open special window named information window. The main
difference from the modal and MDI windows is such window cannot have active state and
so cannot catch lightweight events stream. Actually the window just shows some information
and doesn't participate in a user interaction.
The library extension provides the LwWindow and LwBlankDialog components that is like
standard window. The windows can be used to organize MDI interface.
|