: Download: FAQ: Licensing: Support: Contact ME
LwVCL Home
Introduction
Overview
Screen Shots
On-line Demos
Requirements
Further Plans
Docs
Tutorial
How-to (PDF)
API
FAQ
Download
Latest version

Home > J2SE > Tutorial

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.


Introduction to the Light-Weight Visual Components Library

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.

Is it difficult to use the library?

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
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.

Architecture

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.

Library architecture

The lightweight library has three levels:

  1. 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.
  2. 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.
  3. 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:
    1. 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.

    2. 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.

Lightweight library packaging

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:
  • The sample should inherit LwSample class.
  • The sample should override createSamplePanel method of the LwSample class. The method returns a component which contains your built sample.
  • The sample should contain main method created according to the following pattern:
         ...
         public static void main (String[] args)
         {
            runSampleApp(sampleWidth,
                         sampleHeight,
                         new ());
         }
         ...
        
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.

Lightweight library deployment

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 

       

Deployment steps

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:

  1. 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).
  2. If the "lwvcl.base" property is not specified LwVCL uses "org/zaval/lw/theme/base" as the base directory.
  3. 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".
  4. 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.
  5. If the LwVCL extension package is used, the same procedure is repeated for the "lwext.properties" properties file.

Lightweight properties file format

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:

  • LwVCL applications can specify the property as the environment variable:
        java.exe -Dlwvcl.base=…
                
  • LwVCL applets can specify the property as the applet parameter:
        <applet …>
          <param name="lwvcl.base" value="…">
         …
                

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.

Lightweight Component

Abstraction

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

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. 1. The preferred size is calculated according to metrical characteristics (LwComponent) or according to a layout manager implementation (LwContainer).
  2. 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

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.

Lightweight painting

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:

  1. Validates a component if it is necessary.
  2. 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.
  3. If the component has a view manager that specifies a border view than the view will be rendered.
  4. Calculates a clip area. The clip area is calculated as intersection of the component size (without the component insets) and the current clip bounds.
  5. 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).
  6. If the component has a view manager and the view manager determines a "face" view than the paint manager draws the view.
  7. 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.

Lightweight view management

First of all let's understand what the view is. Often you face with the following two tasks:

  1. 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.
  2. 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:

  1. 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.
  2. 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.
  3. 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.

Lightweight events concept

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:
    1. 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).
    2. 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:
Event distribution mechanism
  1. 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.
  2. The LwDesktop component asks the LwEventManager manager what lightweight component is a source of the originated event.
  3. The LwEventManager manager defines the source according to the mouse cursor location.
  4. The LwEventManager manager looks for a parent composite component
  5. 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.
  6. 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 parent component can listen the child components events by implementing the LwChildrenListener interface. The different from the previous point is the child component gets the event, he is not transparent for the generated event. The parent component gets the child event after the child component has handled it.

    Note: it is impossible to catch some of the child component events. For example, mouse moved event type cannot be caught by the parent component. The reason is the performance issue.

Lightweight validation

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:
    1. As rule, this is the container layout manager who defines the component metrics (preferred size).
    2. 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.

Lightweight static objects

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.

Lightweight scrolling

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.

Lightweight desktop

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:

  1. Mouse pressed event.
  2. 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.

Lightweight application and applet

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"));
    …
  }
  …
}
…

Lightweight windows

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.

: up