Programming Tutorials Browser Tutorials Articles Struts Tutorials Hibernate Tutorials

  Tutorial: Dynamic user interface is only skin deep - JavaWorld May 2000

Dynamic user interface is only skin deep - JavaWorld May 2000

Tutorial Details:

Dynamic user interface is only skin deep
Dynamic user interface is only skin deep
By: By Jason Briggs
Java skins are an alternative approach to a pluggable look and feel
skin is a collection of images and a definition file, which together describe an application interface. You have no doubt come across applications using skins already. On Windows, Linux, and other operating systems, an increasing number of applications (and games) allow users to completely change the look and feel of the user interface. The packages used to implement these design changes are usually called skins.
Winamp -- an MP3 player by Nullsoft (see Resources for more info) -- is one application that uses skins. Nullsoft actively encourages skin development for Winamp, and, according to its Website, more than 5,000 skins are currently available. Games such as Quake III Arena use skins to allow players to select the characters who will represent them during play, and create entirely new characters. Skins even help you alter the look of your operating system desktop according to your whims.
Why should you use skins? Well, if you write applets, especially for the Internet, and cannot guarantee that your user base already has JDK 1.2 installed, or has access to broadband, there is significant overhead with downloading Swing. The same argument applies if you write a downloadable application, or one in which the application size may be an issue.
Another advantage to using skins is you can fit a pre-existing library of lightweight components into a dynamic (skin-based) model without too much pain. If you have ever worked with a designer, then you probably spent hours reworking your layouts to make a minor modification to the interface design. Use a skin, and the design can be altered in a few moments without the need to recompile. Better yet, skins allow you to hand over complete control of the interface layout to your designer.
There are also marketing considerations. Winamp might not have been as popular if more than 5,000 designs were not available for download. But skins' big selling point for me is the fact that after I brand an application for one company, I can rebrand it for another company, or for a shrink-wrapped version, quickly and easily.
Note: to download the complete source code for this article as a zip file or in tar.gz format, see Resources .
How it works
The specification of a basic customizable interface is relatively simple. You'll need:
A new layout manager
A properties file that contains information about how the interface is laid out
An ImageLabel (lightweight) component for noninteractive areas of the screen
An ImageButton (lightweight) component for interactive areas of the screen
Other lightweight components as necessary for the application
The following code samples define the most basic lightweight components -- the ImageLabel and ImageButton . Those who already have a library of lightweight components should skip ahead to the layout manager definition.
ImageLabel.java
The following code implements the ImageLabel lightweight component, rendering an image onto a supplied graphics context. Please note that a utility class -- Utils -- is used for loading images:
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
/**
* A lightweight component which simply renders an image
*/
public class ImageLabel extends Component {
/**
* the image to be rendered
*/
Image image = null;
/**
* set the image for this component
*/
public void setImage(String imageFilename) throws InterruptedException {
image = ImageUtils.getImage(imageFilename);
}
/**
* draw the image onto the Graphics context
*/
public void paint(Graphics g) {
if (image != null)
g.drawImage(image,getLocation().x,getLocation().y,getSize().width,getSize()
.height,null);
}
}
ImageButton.java
The ImageButton component is similar to ImageLabel , but has additional methods for focused and pressed images:
public void setImageFocus(String imageFilename) throws InterruptedException
public void setImagePress(String imageFilename) throws InterruptedException
In addition, ImageButton requires functionality to support interaction:
public void addActionListener(ActionListener listener)
public void removeActionListener(ActionListener listener )
public void processMouseEvent(MouseEvent e)
The layout manager -- SkinLayout.java
SkinLayout is constructed with one of two methods specifying the location of the properties file (either an input stream or a filename):
public SkinLayout(InputStream in) throws IOException
public SkinLayout(String layoutFile) throws FileNotFoundException, IOException
The file is read into a Properties object ready for use. Components can be added to the layout using two methods. The first method conforms to the 1.1 version of addLayoutComponent() . The constraint must be a string. This string is the name of the component and is used to retrieve layout information from the Properties object:
public void addLayoutComponent(Component comp, Object constraints)
public void addLayoutComponent(String name, Component comp)
The positioning and sizing of components in a container are performed by the layoutContainer() method:
public void layoutContainer(Container target) {
synchronized (target.getTreeLock()) {
try {
// call processAttributes for the container itself ("" = no component name)
if (layoutProperties.containsKey("attributes")) {
processAttributes("", target);
}
Enumeration e = components.keys();
while (e.hasMoreElements()) {
String s = e.nextElement().toString();
if (!components.containsKey(s)) {
System.out.println("error. component missing");
}
Component c = (Component)components.get(s);
// minimum attributes need to layout a component
int xpos = new Integer(layoutProperties.get(s +
".xpos").toString()).intValue();
int ypos = new Integer(layoutProperties.get(s +
".ypos").toString()).intValue();
int width = new Integer(layoutProperties.get(s +
".width").toString()).intValue();
int height = new Integer(layoutProperties.get(s +
".height").toString()).intValue();
c.setLocation(xpos,ypos);
c.setSize(width,height);
// visible is not a mandatory attribute, so we check if it's there first
if (layoutProperties.containsKey(s + ".visible") &&
layoutProperties.get(s +
".visible").toString().equalsIgnoreCase("false")) {
c.setVisible(false);
}
// now check for custom attributes
if (layoutProperties.containsKey(s + ".attributes")) {
processAttributes(s + ".", c);
}
}
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
The layoutContainer() method also calls processAttributes() (which is private within the SkinLayout class) to attempt to set other properties on a component, such as its image:
/**
* For a specified component name, find its string of attributes, then
* attempt to find a corresponding set method in the component for each
* attribute. The set method must take a string as its parameter.
* eg. for an attribute string "gobutton.attributes=image=temp.gif,
* text=Test" we will attempt to find a setImage and setText method in
* the component 'gobutton' with a single String parameter
*/
private void processAttributes(String s, Component c) throws Exception {
StringTokenizer st, attr_st;
// retrieve the list of methods
Method methods[] = c.getClass().getMethods();
if (methods != null && methods.length > 0) {
// tokenize the attributes, delimited by comma's
st = new StringTokenizer(layoutProperties.get(s +
"attributes").toString(),",");
// loop for each individual attribute
while (st.hasMoreTokens()) {
attr_st = new StringTokenizer(st.nextToken(),"=");
if (attr_st.countTokens() != 2) {
throw new Exception("invalid attribute string");
}
String attribute = attr_st.nextToken();
String value = attr_st.nextToken();
// find the associated method
// if found, then invoke it with the attribute value
boolean found = false;
for (int i = 0; i if (methods[i].getName().equalsIgnoreCase("set" + attribute) &&
methods[i].getParameterTypes().length == 1 &&
methods[i].getParameterTypes()[0].getName().equals("java.lang.String")) {
found = true;
Object values[] = { value };
methods[i].invoke(c,values);
}
}
if (!found) {
System.out.println("could not find a corresponding method for set"
+
attribute + " in [" + s + "]");
}
}
attr_st = null;
}
st = null;
}
Layout properties file
The properties file will contain some basic information about the application screen, plus all the components used on that screen. The following example includes settings for the application width and height in addition to attributes for one button. These attributes will set the image, the pressed image, and the focused image.
width=230
height=42
back.width=50
back.height=40
back.xpos=0
back.ypos=0
back.visible=true
back.attributes=image=back1_nf.gif,imagepress=back1_press.gif, imagefocus=back1_f.gif
Putting it all together
For testing purposes, TestApplet.java implements part of a toolbar (three buttons), along with two buttons to change the layout of the toolbar. (If you have a browser that supports JDK 1.1, click TestApplet.html to see this applet running.) The init() method of TestApplet is as follows:
public void init () {
try {
// call setup at the beginning so any class can load images using a static 'function' call
Utils.setup(this);
// create a new layout
layout = new SkinLayout(Utils.getFileFromServer(getCodeBase() +
"layout1.properties"));
this.setLayout(layout);
// construct buttons
backButton = new ImageButton();
forwardButton = new ImageButton();
stopButton = new ImageButton();
end = new ImageLabel();
layout1Button = new ImageButton();
layout2Button = new ImageButton();
this.add(backButton,"back");
this.add(forwardButton,"forward");
this.add(stopButton,"stop");
this.add(end,"end");
this.add(layout1Button,"layout1");
this.add(layout2Button,"layout2");
// the action listener used f


 

Read Tutorial at: Click here to view the tutorial

Rate Tutorial:
Dynamic user interface is only skin deep - JavaWorld May 2000

View Tutorial:
Dynamic user interface is only skin deep - JavaWorld May 2000

Related Tutorials:

Sir, what is your preference?
Sir, what is your preference?
 
Facilitate form
Facilitate form processing with the Form Processing API
 
Create a scrollable virtual desktop in Swing
Create a scrollable virtual desktop in Swing
 
Java security evolution and concepts, Part 5
Java security evolution and concepts, Part 5
 
Bridge the gap between Java and Twain
Bridge the gap between Java and Twain
 
Update distributed applications
Update distributed applications
 
Attack of the clones
Attack of the clones
 
Introducing the Portlet Specification, Part 1
Introducing the Get your feet wet with the specification's underlying terms and concepts
 
confusing title
confusing title
 
Isolate server includes' runtime context
Isolate server includes' runtime context
 
Use AOP to maintain legacy Java applications
Use AOP to maintain legacy Java applications This artical shows you how to use aspect-oriented programming (AOP) to gain an unprecedented view into the inner workings of even the most opaque of legacy applications. Please note that this article assume
 
JAligner
JAligner JAligner is an open source Java implementation of the Smith-Waterman algorithm with Gotoh's improvement for biological local pairwise sequence alignment using the affine gap penalty model.
 
Handling Events in JavaServer Faces, Part 2
Here in part two, Hans implements event handling for parts of the sample application discussed in part one.
 
Java validation with dynamic proxies
Decouple validation processes from your business object implementations.
 
Jurassic Phoenix - reviving yesterday\'s data
Jurassic Phoenix - reviving yesterday\'s data Jurassic Phoenix is a simple solution to the problem of evolution of serialized data. Why use Jurassic Phoenix? The frustration Serialization is great for persistence, because it is automatic, dynamic and
 
Java Resources
There are all Java freebies. Some of these are old, and not under maintenance. Download and use them at your risk. In case of queries, mail subrahmanyam_avb@technologist.com or varalakshmi_a@techie.com.
 
Java Server Pages Dynamically Generated Web Content.
JavaServer PagesTM (JSP TM) technology allows Web developers and designers to rapidly develop and easily maintain, information-rich, dynamic Web pages that leverage existing business systems.
 
Java theory and practice: Generics gotchas
Generic types, added in JDK 5.0, are a significant enhancement to type safety in the Java language. However, some aspects of generics may seem confusing, or even downright bizarre, to first-time users. In this month's Java theory and practice, Brian Goetz
 
Advanced Synth
Take an in-depth look at the Synth look and feel, the newest addition to Swing introduced in Java 5.0. Synth lets developers rapidly create and deploy custom looks for an application by introducing the concept of a "skin" to Java UI programming.
 
New Technical Articles: 64-bit Programming on Solaris 10 OS for x86 Platforms
Four technical articles describe the new Sun Studio 10 software's 64-bit programming features on the Solaris 10 OS for x86 and AMD64 platforms. Important issues regarding the AMD64 ABI (Application Binary Interface), debugging, migration to 64-bits, and p
 
Site navigation
 

 

Send your comments, Suggestions or Queries regarding this site at roseindia_net@yahoo.com.

Copyright © 2006. All rights reserved.