Java Look and Feel

paltryboarpigSoftware and s/w Development

Nov 3, 2013 (3 years and 9 months ago)

83 views

William Pohlhaus

Java Look and Feel

1

Introduction

................................
................................
................................
.........................

2

Overview of Look and Feel

................................
................................
................................

3

Look and Feel Foundation Classes

................................
................................
.....................

5

UIManager class

................................
................................
................................
.............

5

LookAndFeel class
................................
................................
................................
..........

6

UIDefaults class

................................
................................
................................
..............

7

UIResource interface

................................
................................
................................
......

8

Basic Look and Feel
................................
................................
................................
..........

10

Through Color

................................
................................
................................
...............

10

Through Components
................................
................................
................................
....

12

Through UI Classes
................................
................................
................................
.......

14

UI Class

................................
................................
................................
.............................

15

Methods
................................
................................
................................
.........................

16

Conclusion

................................
................................
................................
........................

18

Appendix A: UML Sequence Diagram
................................
................................
.............

19

Appendix B: System Color Reference

................................
................................
..............

20

Appendix C: BlueButtonUI class
................................
................................
......................

21

Appendix D: Resources

................................
................................
................................
....

24

William Pohlhaus

Java Look and Feel

2

Java Look and Feel

Introduction

Java Swing allow
s

for the creations for of an independent look and feel of the
graphical user interface (GUI) from the functionality of that GUI. This allows for great
freedom for development of GUIs and t
he look and feel of the GUI.
It provides a way for
quicker application development by separating the look and feel from the functionality,
because two teams can work simultaneously

on a project

with little interaction.

Note:

The reader of this paper shoul
d have an understanding of Java Swing and the Java 2D API
before
proceeding
.
U
nderst
an
d
, also,

that the reader
should

reference both the Java J2SE
API and PowerPoint presentation for this paper.


Of the many questions tha
t might come up when thinking about customizing a look
and feel the most important is “why bother?


There
are
several answers to this question
depending on the context that the developer faces
. If the developer is a game developer
then the answer is simp
le
;

the designs of the current look and feels available are not good
for games. A

good reason
to bother
is marketability of the application. A company wants
their applications to stand out
from

the rest. Customizing a look and feel allows for
dist
inct look and feels that may include company logos and trademarks.
Moreover, the
application might not be running on a personal computer and therefore the only option is
a customized look and feel because the standard ones are for personal computers.

William Pohlhaus

Java Look and Feel

3


Ove
rview of Look and Feel

In order to understand how to make a

pluggable

look and feel package
,

the look and
feel developer

must
, first,

understand how
Java accomplishes
look and feel

for its Swing
components
.

Java separates
Swing into

two set of classes
:

lig
htweight and heavyweight
.
The heavyweight
classes delegate painting to

the operating system

with some user input
depending on how much control the operating system hands over to the user. These
classes consist of all the top level classes:
JFrame,
JDialog, JWindow, and JApplet
. The
other set of classes are the Java Swing lightweight classes which all inherit from
JComponent
and delegate

the pa
inting

to

a

separate UI class.

When a lightweight Swing
class is

i
nstantiate
d
, it calls the UIMan
ager
to retrieve the UI class that is responsible for
painting that particular class to the graphical device from the UIDefaults class.

The
UIManager gets the UIDefaults class from the LookAndFeel class that is set by the
setLookAndFeel method.

While m
uch

of this seems confusing, it isn’t
.

Especially,
once

an understanding of

all the individual pieces is accomplished
.

Appendix A shows a UML
sequence diagram of this.


To get started on creati
ng a pluggable look and feel
,

the look and feel developer

must d
ecide between two design methods of creating a look and feel in Java. One is to
create the look and feel by extending the javax.swing.plaf package the other is to extend
an existing look and feel package
,

usually javax.swing.plaf.basic
.

It not recommended

extending a look and feel from the javax.swing.plaf
if the look and feel is going to be for
a personal computer.
This is because the javax.swing.basic package has extended almost
the entirety of the javax.swing.plaf package

for the developer to use
.

Thi
s allows
the look
William Pohlhaus

Java Look and Feel

4

and feel developer to pick and choose which things about the look and feel to customize
without having to extended and implement everything.

Further, in its implementation of
th
e java.swing.plaf package
a basic principle
i
s followed
that allow
s

for customizing a
look and feel very easily. This principle is the centralization of components, color and UI
classe
s within the LookAndFeel class. And finally, the javax.swing.plaf.basic package
paints the lightweight Swing componen
ts in
expected

ways.

However,
the
recommendation changes if

the look and feel developer is creating a look and feel for a
device other than the computer screen
.

T
hen
the preferred method is
extending the
javax.s
wing.plaf package from scratch
.


T
here are
some
foundation

classes

to look and feel in Java that the look and feel
developer must be

aware of and understand
,

with


respect to look and feel,

before the
developer can understand the methodologies for customizing look and feel in Java.
These
cla
sses are the UIManager class, the LookAndFeel class, the UIDefaults class, the
UIResource interface and the UI classes. With a mastery of these classes the look and feel
developer can customize the
look

and feel any way s/he wants.

William Pohlhaus

Java Look and Feel

5

Look and Feel Found
ation Classes

UIManager

class

The UIManager class is responsible

for setting

and changing

the pluggable look and
feel

for
the lightweight Swing classes

through its setLookAndFeel method.

To set a
pluggable look and feel the developer calls

on the

UIManage
r.setLookAndFeel static
method. Passed to the method is a Sting argument or an instance of a LookAndFeel class.
If it is a String argument that String should be the fully qualified name of the
LookAndFeel class for the pluggable look and feel. If the devel
oper was setting the Metal
look and feel s/he would pass either the String

“javax.swing.plaf.metal.MetalLookAndFeel” or new
javax.swing.plaf.metal.MetalLookAndFeel().

In order to switch the pluggable look and
feel
the developer sets the new look and feel
and then calls the
javax.swing.S
wingUtilities
’s method
updateComponentTreeUI
(Component c) on the top
level Swing component
s
, the component
s

that
are

holding all the other Swing
components
.

Th
e
s
e

are

usually
one of the

heavyweight Swing class, JWindo
w, JFrame,
JApplet or
JDialog
. The reason for this is that each lightweight Swing class needs to
update its UI class. The
updateComponentTreeUI
(Component c) notifies the lightweight
Swing classes to allow for just that.

The UIManager class

is, also

r
esponsibl
e for
retrieving the UI classes from the pluggable look and feel
, through its static method
getUI(JCompnent c),

and

set
ting th
ose UI classes

for
the

lightweight Swing class
es
.

This
is achiev
ed by retrieving the UIDefaults class from the LookAndFeel class and getting
the UI class from the UIDefaults class.

The following code switches a look and feel from Blue to Metal:

UIManager.setLookAndFeel(new
William
.swing.plaf.blue.BlueLookAndFeel
());

William Pohlhaus

Java Look and Feel

6

JFrame f = new JFrame();



UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");

SwingUtilities.updateComponentTreeUI(f);


LookAndFeel class

The center of the look and feel is the LookAndFeel class. This class holds all the
meta

inform
ation and sets all the customization of the look and feel to the UIDefaults class.

There are five abstract methods that must be implemented:
getDescription()
,
getID()
,
getName(), isNativeLookAndFeel() and isSupportedLookAndFeel().
The
getDescription() meth
od will return a description of the look and feel. The getID()
method will return the ID for the look and feel

that applications and services can use to
identify it. T
he getName() method will return the name of the look and feel. The Java
API notes that if

the developer is extending an existing look and feel, such as Motif,
Metal, Windows or Mac, but “doesn't make any fundamental changes”

(Java API)

then
getID() should not be modified but
getName()
should note a difference to identify the
extended look and
feel from the parent look and feel. For example if the developer
extended Metal i
n

such a way
th
en

the getID() would still return “Metal” but the
getName() might return “Blue Metal”. The isNativeLookAndFeel() method should return
true if the look and feel

is the native look and feel for that operating system, i.e. the
Windows look and feel returns true on Windows machines. The
isSupportedLookAndFeel() method

will return true if the underlying operating system
supports this look and feel
.
It

usually will
only return false i
f

there are legal reasons.
Cross platform look and feels will usually always return true
.

The Metal look and feel returns the following meta information on a Windows machine:


Name:



Metal

ID:



Metal

Description:
The Java(tm) Look
and Feel

Is Native:
false

Is Supported:
true


William Pohlhaus

Java Look and Feel

7



There are three other methods that the developer might want to consider
overriding: initialize(), uninitialize() and
provideErrorFeedback(Component c)
.
The
initialize() method is called by the UIManage
r class before i
t

gets the UIDefaults class
and is used to set varies aspects of your look and feel. On the reverse side is the
uninitialize() method
.
This

is called the before replacing the look and feel and use
d

to
unset varies aspects of the look and f
eel. The
provideErrorFeedback(Component c)

is
called when an illegal action is preformed by the user
“such as pasting into an uneditable
JTextField
that has focus” (
Java API
).

UIDefaults class


The UIDefaults class is a hash table of all the pieces of the

look and feel.
It is this class
to which

the developer will add all the components of the look and feel

and
from which

the UIManager will retrieve components
. The UIManager will get the
UIDefaults class from the LookAndFeel class of the lo
ok and feel package through the
getDefaults() method of the LookAndFeel class. The UIDefaults class is made of
key/value pairs, where the key is
al
most always a String and the value

usually

implements the UIResource interface
. I
f the value is a UIResource
then it is almost
always a

component object (Insets, Color, UI Class, etc.)

and when it does not implement
UIResource t
hen it is almost always a String
. In order to set the key/value pair the
developer will need to create

a single di
mensional Object array that contains the keys and
values by alternating between key and the value to that key. Then, once the array is
create
d
,
it is passed

to the putDefaults(Object[] objs) method of the UIDefaults
object
.


William Pohlhaus

Java Look and Feel

8

Example of such an
array:

/* Adding two key values to table */

UIDefaults table



Object[] key_values = new Object[4];

key_values[0] = “desktop”;




// 1st key

key_values[1] = “#FFFFFF”;




// 1st key’s value

key_values[2] = “Button.margin”;



// 2nd key

key_values[3] =

new InsetsUIResource(1,1,1,1);
// 2nd key’s value

table.putDefaults(key_values);


Or


UIDefaults table



Object[] key_values = {

/*

Key



Value */


“desktop”,


“#FFFFFF”,


“Button.margin”,

new InsetsUIResource(1,1,1,1)

};

table.putDefaults(key_values);


Many of the key/value

pairs within the UIDefaults class will only be used internally to
the look and feel package

and
will be

created by the developer for the developer’s use.

However, it is this class that holds the matching between the UI classes a
nd the
UIClassID’s that the lightweight Swing classes use to obtain the UI class from the
UIManager. Therefore, the developer is obligated to set all the UI classes key/value pairs
for the lightweight Swing class.
The methodology behind the UIDefaults clas
s is that

this
class allows the developer to centrally control the look and feel by having the UI classes
pull default values

for components

from
the UIDefaults

through the UIManager’s static
methods.

So while only the UIClassID/UI class
pairs

need be set, it behooves the
developer to set all the default components (insets, colors, borders, etc.) to key/value
pairs with
in this class.

UIResource interface

The UIResource interface

is an interface that has no methods to implement. Its use is
that
of a flag. It

allows the developer
of the

look and feel package, if the developer
implements it, to distinguish between user set components

(
colors, icons, etc.
)

of a
lightweight Swing class and those components set by the look and feel. Through this
William Pohlhaus

Java Look and Feel

9

distinguishing the developer and
the
look and feel package can allow the user to override
the look and feel components for a particular instance of a lightweight Swing object.

This
way when a look and feel is set for an application in which the Swing devel
oper has set
different components on different objects
,

those changes to those particular objects will
not be overwritten by the look and feel.

All of the default components within the current
look and feels implement this interface and therefore the devel
oper is strongly
encouraged to do the same for her/his components.
In order to obtain this distinguishing
the developer must call instanceof UIResource on the object in question.

There are
several classes that implement this interface for
convenience: Icon
UIResource,
BorderUIResource, etc.

Example of distinguishing UIResource:

Color ba
ckground = UIManager.getColor(“B
utton.background”);

if(c.getBackground()==null || (c.getBackground() instanceof UIResource))


c.setBackground(background);


William Pohlhaus

Java Look and Feel

10

Basic Look

and Feel


To

understand the rest of customizing a look and feel
, and the last type of
foundation class (UI classes),

we will talk in relation to extending the
javax.swing.plaf.basic look and feel package. To

extend the javax.swing.plaf.basic the
developer

will first extend the BasicLookAndFeel class into his/her own LookAndFeel
class

and implement the five abstract methods
.
This gives the developer a compliable
look and feel package that will paint all the lightweight Swing classes. This is because
the
dev
eloper
has
, at his/her disposal,

an implementation of every UI class

by extending the
javax.swing.plaf.basic look and feel package. But more importantly
,

extension

of the
javax.swing.plaf.basic package

allows for three distinct methodologie
s of

cu
stomizing

th
e
look and feel
: through

color
, t
hrough components

and/or through

CompnentUI classes

(UI classes).
The developer may a
pply each alone or together with one or two of the other
methodologies. The BasicLookAndFeel class breaks these into three methods:

in
itSystemColorDefaults(UIDefaults table)
,
initComponentDefaults(UIDefaults table)

and
initClassDefaults (UIDefaults table)
;

each is responsible for a different methodology.

Through Color


The first, and easiest, way to customize the look and feel is throug
h color. When
extending the BasicLookAndFeel class th
e developer is given a method that

encapsulate
s

this particular way of customization, the
initSystemColorDefaults(UIDefaults table)

method. To do this customization the developer will associate system co
lor keys with
UIResource color objects

or String object representing color using the HTML format for
color, #RRGGBB.
I
f setting ColorUIResource, a convenience Color class that
implements UIResource, objects as values
t
hen the developer will

add the

object array to
William Pohlhaus

Java Look and Feel

11

the UIDefaults table
or

if using String
representations

of color

call
s

the
loadSystemColors(
UIDefaults
table,

Object[]

colors,

boolean native
)

method of the
BasicLookAndFeel class. This method
converts the Strings to ColorUIResource objects
and set
s

the system colors the developer did not set.
The first two arguments of the
method are obvious, the last argument
, the boolean argument,

is true if the developer
wants the changes to be overwritten b
y the operating system’s native colors
;

but
,

most of
the time
,

the developer does not want this so it will be

set to

false.
The determining factor
in using one method o
r

the
other

is whether or not the developer will be setting all

or
some of

the syst
em colors
.


I
f s/he is
setting all the colors
the
former method should be
used otherwise the latter should be used.

By setting vari
ous

keys the developer has color
control of
various

groupings of components of lightweight Swing objects. With

a little
trail and error
,

mastering this method of customization is easy.
Appendix
B

gives a quick
reference

to system colors
.

Example of setting every system color:

p
rotected void initSystemColorDefaults(UIDefaults table) {


ColorUIResource pr1 = new Col
orUIResource(new Color(127,127,255));


ColorUIResource pr2 = new ColorUIResource(new Color(0,0,127));


ColorUIResource pr3 = new ColorUIResource(new Color(63,63,191));


ColorUIResource pr4 = new ColorUIResource(new Color(0,0,255));


ColorUIResource blk = n
ew ColorUIResource(Color.BLACK);


ColorUIResource wht = new ColorUIResource(Color.WHITE);


ColorUIResource gry = new ColorUIResource(Color.GRAY);


Object[] colors = {


"desktop" , pr1,
/* Color of the desktop background */


"activeCaption"



, pr3,
/* Color for captions (title bars) when they are active. */


"activeCaptionText"

, wht,
/* Text color for text in captions (title bars). */


"activeCaptionBorder" , blk,
/* Border color for caption (title bar) window b
o
rders. */


"inac
tiveCaption" , pr1,
/* Color for captions (title bars) when not active. */


"inactiveCaptionText" , gry,
/* Text color for text in inactive captions (title bars). */


"inactiveCaptionBorder", gry,
/* Border color for inactive caption (title bar) wi
ndow borders. */


"window" , wht,
/* Default color for the interior of windows */


"windowBorder" , blk,
/* Color of the window border */


"windowText" , blk,
/* Color of the window text */


"menu" , pr1,

/* Background color for menus */


"menuText" , blk,
/* Text color for menus */


"text" , pr1,
/* Text background color */


"textText" , blk,
/* Text foreground color */


"textHighlight" , pr4,
/* Text ba
ckground color when selected */


"textHighlightText" , wht,
/* Text color when selected */


"textInactiveText" , gry,
/* Text color when disabled */


"control" , pr1,
/* Default color for controls (buttons, sliders, etc) */


"contro
lText" , blk,
/* Default color for text in controls (buttons, sliders, et
c
) */


"controlHighlight" , pr4,
/* Highlight color for controls */


"controlLtHighlight" , wht,
/* Lighter highlight color for controls */


"controlShadow" ,

pr2,
/* Shadow color for controls */


"controlDkShadow" , blk,
/* Dark shadow color for controls */

William Pohlhaus

Java Look and Feel

12


"scrollbar" , pr3,
/* Scrollbar background (usually the "track") */


"info" , wht,
/* Background color for informationa
l text */


"infoText" , blk
/* Color for informational text */


};


table.putDefaults(colors);

}


Example of setting only some system colors:

protected void initSystemColorDefaults(UIDefaults table) {


Object[] colors = {


"desktop
"
,

"
#CC5500
"
,



"activeCaption
"
,

"
#FFFFFF
"
,




"activeCaptionText
"
,

"
#000000
"



};


loadSystemColors(table, colors, false);

}


Through Components


It becomes evident, however, that the precedin
g method is limited.

So this leads to
the next method of customizing look and feel, through components.

To achieve this the
developer overrides the
initComponentDefaults(UIDefaults table)

method.
Within this
method the developer associates components with
particular keys that the UI classes will
use to retrieve the

default values of those components.
The
convention

for the key
naming is to name it

by the

type of

ComponetUI class that is going to use it

and the
component’s
type
, i.e.
key “button.border
” would be the border component used by the
ComponentUI button class
. To truly master this methodology the developer should
become familiar with
implementing
all the different components
, borders, icons, fonts,
insets, etc.

It is easiest to create a factor
y class that will return instances of your
components, which will be inner classes of your factory class
.
This approach is best if
you have multiple
types of a particular component.
This is because all types of a
component will be

centrally located in one
class so the management is easier
.

For
example,

all your borders will be inner classes of and created by your border factory
class
.

Just as the developer centralizes the colors, components and UI classes to the
UIDefaults table so a factory class centraliz
e
s

the management of a
particular type of
William Pohlhaus

Java Look and Feel

13

component.

This
methodology, customizing through components,

is best for customizing
check boxes, radio buttons and/or other ic
on based components because
it is the icon that
makes those lightweight Swing classes u
nique.

An

illustration of this
is
in the following
example
(
see figure 1

below

to see the effects

of changing the check box icon.
)

Note
that
the every color component by default
is mapped
to one of the system colors
, which were
set by the initSyst
emColorDefault
s

method,

by the javax.swing.plaf.basic package.
Therefore, it is advisable that the developer not set color components unless s/he has truly
thought it over or wants more exacting control over a particular UI class color.

See Java
Swing 2nd
Edition by O’Reilly Appendix A for a complete list of all the components set
by the BasicLookAndFeel

class.

Example of setting components:

protected void initComponentDefaults(UIDefaults table) {


super.initComponentDefaults(table);


Object[] compone
nts = {


"CheckBox.icon" , new CheckBoxIcon(),


"Button.background", pr4,


"Button.foreground", wht,


"Button.font" , new Font("Times",Font.BOLD|Font.ITALIC,10)
,


"RadioButton.icon"

, IconFactory.getRadioButton()



};


table.putDefaults(components);


}


Note
:


T
hat super.initComponentDefaults(table) was called here but not in the
initSystemColorDefaults method.


Figure 1: illustrating how changing a
n icon can completely change the look and feel of
the JCheckBox



Notes about images:


Where images should be located


William Pohlhaus

Java Look and Feel

14

All the images that the look and feel uses should be located within the package directory
struc
ture. The developer can obtain an URL object representing the locate of a resource
relative to your class path by invoking this.getClass().getResource(String relative_path)
method.

Example of a relative_path:

“/william/swing/plaf/blue/checked.gif”

where t
he package is:

william.swing.plaf.blue.*


How to load images


Use the javax.swing.ImageIcon class for retrieving Images will guaranteed the image will
be loaded in the Image object when getImage() method is called on this object. This is
easier and safer t
han use the DefaultToolkit from the java.awt.Toolkit class for loading
images


Through UI Classes


Though the
preceding

method
ology

of customization gives even greater control it
is still limited.

For example, the developer cannot achieve rounde
d buttons through
changing components.

Hence, the last methodology of customization of look and feel
gives the developer full control of the painting of the lightweight Swing object to the
developer, through UI classes. To achieve this the developer must o
verride the
initClassDefaults
(UIDefaults table)

and set the key/value pairs of the UI classes
, which
the developer has developed,

to lightweight Swing class the developer wishes to change.

The keys will be
the String returned by t
he lightweight Swing class
’s
getUIClassID()

method and the values will be the
a

String that holds the fully qualified name
, the
package name plus the class name ,

of the UI class.
The convention for naming the UI
class is
name of the look and
feel + UIClassID of the lightweight Swi
ng class.
This
methodology is best for those lightweight Swing classes that can not be customized to the
developer’s needs through one of the first two methodologies.





William Pohlhaus

Java Look and Feel

15

Example of setting UI classes:

protected void initClassDefaults(UIDefaults table) {



super.initClassDefaults(table);


//package that the ComponentUI classes belong too


String pkg = "william.swing.plaf.blue.";


Object[] classes = {


"RootPaneUI", pkg + "BlueRootPaneUI",


"PanelUI" , pkg + "BluePanelUI",


"MenuBarUI" , pkg + "BlueMenuBarUI",


"MenuUI" , pkg + "BlueMenuUI",


"ButtonUI" , pkg + "BlueButtonUI"


};


table.putDefaults(classes);


}


UI Class


The UI class, or ComponentUI class, is the class that is ultimately responsible for

painting
how
the lightweight Swing objects

is going to look

to the graphical device.
Fortunately for the developer the javax.swing.plaf.basic package has implemented each
of the ComponentUI classes for each lightweight Swing class; this leaves the develop
er
free to focus on painting the lightweight Swin
g object. In order to create a ComponentUI
class

the developer needs only

to extend the ComponentUI class s/he wants to create
from the javax.swing.plaf.basic package and

override one method, the
createUI(JC
omponent c)

method
.
In overriding this method the developer has two
choices

of

the type of object to return. The developer can return a singleton or can return
a new instance of the object.

The developer should be familiar with return
ing

a new
ins
tance.

To return a singleton
1

the developer returns a static class variable of the
ComponentUI. The advantage of th
is is that it will take up less memory
,

but the trade
-
off
is every lightweight Swing class that uses this singleton will share the same state

information. However, this can be
overcome

by using the lightweight Swing object to
hold the state information for look and feel.

Returning a singleton is the preferred
method.

Only when the lightweight Swing object can not hold absolutely critical state



1

An object in which there is only
one instance of it in memory

William Pohlhaus

Java Look and Feel

16

information and the developer knows there will be a low number of instances of this
object is returning a new instance acceptable.

Examples of singleton and new instance:

//From william.swing.plaf.blue.BlueButtonUI

//which is
responsible

for painting JBut
tons



//As a singleton.


//Note the static class variable


private static BlueButtonUI blueButtonUI = new BlueButtonUI();





public static ComponentUI createUI(JComponent c) {


return blueButtonUI;


}



Or



//As a new instance


public static

ComponentUI createUI(JComponent c) {


return new BlueButtonUI();


}



The developer has now created a ComponentUI class but has not customized it. In order
to customize the ComponentUI the developer needs to be aware of a few other methods.
These are

installUI(JComponent c), uninstallUI(JComponent c),
the sizing methods
(
getMinimumSize()
,
getMaximumSize()
,
getPreferredSize()
), and most importantly
paint(Graphics g, JComponent c)
.

Methods

The installUI(JComponent c) method is called by the lightweig
ht Swing object
when it sets the ComponentUI and passes itself to the method.

It is used to set the JComponent’s look and feel state information through i
t
s look and
feel set methods, i.e. setBackground(Color bg), if the user has not set those properties.

This can be checked by retrieving the information from its look and feel get methods, i.e.
getBackground(), and doing instanceof UIResource if true then the user has not set the
property. If the user has not set a particular property then the developer sh
ould set it by
retrieving the default value from one of the appropriate static method
s

from UIManager,
i.e. getColor(Object key).
(See code for checking UIResourse) The other two functions to
William Pohlhaus

Java Look and Feel

17

be preformed by this method
are

to install listeners on the JC
omponent for setting its
function state information and registering keyboard actions. More often then not if the
developer is extending the javax.swing.plaf.basic package then this method won’t be
overwritten
, and even if the developer does overwrite this
method the
javax.swing.plaf.basic class s/he is extending will most likely have an
installListeners(JComponent c) method. On the reverse side, the uninstall(JComponent c)
is called before a new ComponentUI class is set on the old ComponentUI class and is
u
se
d

to remove any listeners, keyboard actions and defaults.
T
he developer
probably

won’t override this method. The sizing methods,
getMinimumSize()
,
getMaximumSize()

and
getPreferredSize()

are used by varies layout managers for finding

sizing of the
JComponent, however some layout managers ignore these, i.e.
GridLayout and
BorderLayout
.
Finally
,

the most important method for customizing a look and feel for a
JComponent,

is

the
paint(Graphics g, JComponent c)
.
The developer is expected t
o obtain
most of state information, both functional (is the button pressed) and graphical (what type
of borders to use), from the JComponent c object that is passed in and paint it to the
Graphics g object.
Appendix
C

shows the william.swing.plaf.blue.Blue
ButtonUI class
which shows these methods and shows the use of some other useful classes.







William Pohlhaus

Java Look and Feel

18

Example of a simple RootPanelUI class that

will always have a dark blue background
:

package william.swing.plaf.blue;


import java.awt.Color;

import java.awt.Grap
hics;

import javax.swing.JComponent;

import javax.swing.JRootPane;

import javax.swing.plaf.ComponentUI;

import javax.swing.plaf.basic.BasicRootPaneUI;


public class BlueRootPaneUI extends BasicRootPaneUI {



public BlueRootPaneUI() {


super();


}



p
ublic void paint(Graphics g, JComponent c) {


JRootPane p = (JRootPane)c;


//Note the user can not
change the background color of the JRootPanel


//developers should stay away from the practice of force components on the


//user


g.setColor(
new Color(0,0,127));


}



public static ComponentUI createUI(JComponent c) {


return new BlueRootPaneUI();


}

}


Note on
transparence
:

The
effects

of setting the alpha bit in
J
ava for the Color object

can result in
unpredicted effects so
the devel
oper is advised to use it will caution.



Conclusion


That is how Java look and feel can be created and with a some practice and
exploration of different lightweight Swing classes the developer can truly call himself or
herself a look and feel developer.

However, there is still future research that needs to be
done on developing a look and feel for Java Swing. Those topics are GTK for Java 1.4,
lazy and active values and how motion is achieved. Java 1.4 allows for the creation of
look and feel through the

GTK+, a GNU project for creating a toolkit for creating user
interfaces (
http://www.gtk.org/
). Lazy and active values are types of UIResources that are
loaded differently depending if it is lazy or active. The final topic for future research is
how motion

is achieved in Java look and feel, how are frames painted for minimization or
how are menus scrolled? Even so, with these methodologies the look and feel discussed
here the developer can completely create the look and feel s/he wants.
William Pohlhaus

Java Look and Feel

19

Appendix A:

UML Se
quence Diagram

UML Sequence Diagram showing how a JComponent or lightweight Swing object sets a
ComponentUI or UI object:




Marc Loy, Robert Eckstein, Dave Wood, James Elliott and Brain Cole,

Java Swing
, 2nd,
(Sebastopol: O’Reilly, 2003), 1012.


William Pohlhaus

Java Look and Feel

20

Appendi
x B:

System Color Reference


desktop



Color of the desktop background

activeCaption



Color for captions (title bars) when they are active

activeCaptionText


Text color for text in captions (title bars)

activeCaptionBorder


Border
color for caption (title bar) window borders

inactiveCaption


Color for captions (title bars) when not active

inactiveCaptionText


Text color for text in inactive captions (title bars)

inactiveCaptionBorder

Border color for inactive caption (title bar) win
dow borders

window



Default color for the interior of windows

windowBorder


Color of the window border

windowText



Color of the window text

menu




Background color for menus

menuText



Text color for menus

text




Text background color

textText



Text

foreground color

textHighlight



Text background color when selected

textHighlightText


Text color when selected

textInactiveText


Text color when disabled

control




Default color for controls (buttons, sliders, etc)

controlText



Default color for text
in controls (buttons, sliders, etc)

controlHighlight


Highlight color for controls

controlLtHighlight


Lighter highlight color for controls

controlShadow


Shadow color for controls

controlDkShadow


Dark shadow color for controls

scrollbar



Scrollbar backg
round (usually the "track")

info




Background color for informational text

infoText



Color for informational text


Marc Loy, Robert Eckstein, Dave Wood, James Elliott and Brain Cole, Java Swing, 2nd,
(Sebastopol: O’Reilly, 2003), 1059. and Java Source Co
de for
javax.swing.plaf.basic.BasicLookAndFeel Sun Mircosystems Inc.

William Pohlhaus

Java Look and Feel

21

Appendix C
:

BlueButtonUI class

The william.swing.plaf.blue.BlueButtonUI class

package william.swing.plaf.blue;


import java.awt.*;

import java.awt.image.*;

import javax.swing.*;

import j
ava.awt.geom.*;

import javax.swing.plaf.*;

import javax.swing.plaf.basic.*;

import javax.swing.text.View;



public class BlueButtonUI extends BasicButtonUI {



//The singleton istance of BlueButtonUI


static BlueButtonUI b = new BlueButtonUI();


//Defau
lt background and foreground


Color background;


Color foreground;


//There will be only one font for this these buttons


Font font;



public BlueButtonUI() {


super();


}




//The factory method returns the singleton


public static ComponentUI cr
eateUI(JComponent c) {


return b;


}


public void installUI(JComponent c) {


//Since we know this is a JButton it is safe to cast as an AbstractButton


AbstractButton b = (AbstractButton)c;



//Setting the default values from the UIDefaults
table


background = UIManager.getColor("Button.background");


foreground = UIManager.getColor("Button.foreground");


font = UIManager.getFont("Button.font");



//Checking for user set values for foreground and background before setting th
em


//Note that the font compnonent is not checked therefore the value from the UIDefaults table will


//override the user’s values (This is not recommended) further not all the defaults are set


if(c.getBackground()==null || (c.getBackground() in
stanceof UIResource))


c.setBackground(background);



if(c.getForeground()==null || (c.getForeground() instanceof UIResource))


c.setForeground(foreground);




//Using BasicButtonUI installListeners method to install listeners


super.
installListeners(b);




/*Note that there are no keyboard registations, therefore hit any of the keys will not invoke an
event*/


}

//Paints a rounded button that is semi
-
transparent with lines


public void paint(Graphics g, JComponent c) {


//Onc
e again it is safe to cast as an AbstractButton because we know it is a JButton



AbstractButton b = (AbstractButton)c;


//The ButtonModel holds a lot of the functional state of the button


ButtonModel model = b.getModel();


//Casting to a Graphi
cs2D for convenience, this is safew because we know that the g object is really a
Graphics2D object


Graphics2D g2 = (Graphics2D)g;



//Sets the arcs widths and heights


int arc_w = (int)c.getHeight()/2;


int arc_h = arc_w;



Insets i = c.ge
tInsets();


//Gets the area for the text and icon to be painted in with respects to the insets


Rectangle viewRect = new Rectangle(i.left,i.top,b.getWidth()
-
(i.right+i.left),b.getHeight()
-

(i.bottom
+ i.top));

William Pohlhaus

Java Look and Feel

22


//the area that the text will be dr
awn in that will be defined


//by SwingUtilities.layoutCompoundLabel


Rectangle textRect = new Rectangle(0,0,0,0);


//the area that the icon will be drawn in that will be defined


//by SwingUtilities.layoutCompoundLabel


Rectangle iconRect =

new Rectangle(0,0,0,0);



//I have opted to set the base font size on the size of the button this will cause the font size to
skrink or grow with respect to the button size


int fontSize = (int)c.getHeight()/3;


if(fontSize<8)


fontSize = 8;


g2.setFont(new Font(font.getName(),font.getStyle(),fontSize));


//modify text for display, will add ... if clipped and


//determine the text area and icon area


String text = SwingUtilities.layoutCompoundLabel(


c, g2.getFontMetric
s(), b.getText(), b.getIcon(),


b.getVerticalAlignment(), b.getHorizontalAlignment(),


b.getVerticalTextPosition(), b.getHorizontalTextPosition(),


viewRect, iconRect, textRect,



b.getText() == null ? 0 : b.getIconTextG
ap());



//Starting with a BufferedImage because the graphics object from a BufferedImage respects composite
overlay directives


//NOTE the Graphics object passed in to this method does not respect these directives


BufferedImage buffImg = new Buf
feredImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_ARGB);


Graphics2D gbi = buffImg.createGraphics();


//Retrieving the state of the colors from the component which were set in the installUI method


Color back = c.getBackground();


Color fore = c.getForeground();



//creating a semi
-
transparent background for the button


Color bg = new Color(back.getRed(),back.getGreen(),back.getBlue(),127);


//Defining the color of my borders


Color wh = Color.WHITE;


Color gr = Color
.GRAY;


//if button is pressed change the background to dark and switch the border colors (this makes it appear
that the button is pressed in)


if (model.isArmed() && model.isPressed()) {


Color d = back.darker().darker().darker();


bg = ne
w Color(d.getRed(),d.getGreen(),d.getBlue(),127);


wh = Color.GRAY;


gr = Color.WHITE;


}



//set background color


gbi.setColor(bg);


gbi.fillRoundRect(0,0,c.getWidth(),c.getHeight(),arc_w,arc_h);


//lay in the strips


gbi.setC
olor(Color.BLACK);


gbi.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN,1.0f));


gbi.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);


for(int j=0;j<c.getHeight();) {


gbi.fillRect(0,j,c.getWi
dth(),2);


j=j+4;


}



//paint button image


g2.drawImage(buffImg,0,0,c);


//Draw borders (NOTE a better implementation would have created a borders object)


g2.setColor(wh);


g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, Rend
eringHints.VALUE_ANTIALIAS_ON);


g2.setStroke(new BasicStroke(2.0f));


Arc2D.Double ar1;


ar1 = new Arc2D.Double(0,0,arc_w,arc_h,90,90,Arc2D.OPEN);


g2.draw(ar1);


ar1 = new Arc2D.Double(c.getWidth()
-
arc_w,1,arc_w,arc_h,0,90,Arc2D.OPEN);



g2.draw(ar1);


g2.fillRect(arc_w/2
-
2,0,c.getWidth()
-
arc_w+2,2);


g2.fillRect(0,arc_h/2
-
2,2,c.getHeight()
-
arc_h+2);



g2.setColor(gr);


ar1 = new Arc2D.Double(c.getWidth()
-
arc_w,c.getHeight()
-
arc_h,arc_w,arc_h,270,90,Arc2D.OPEN);


g2.draw(a
r1);


ar1 = new Arc2D.Double(0,c.getHeight()
-
arc_h,arc_w,arc_h,180,90,Arc2D.OPEN);


g2.draw(ar1);


g2.fillRect(c.getWidth()
-
1,arc_h/2
-
2,1,c.getHeight()
-
arc_h+8);


g2.fillRect(arc_w/2
-
8,c.getHeight()
-
2,c.getWidth()
-
arc_w+16,2);



//painting t
ext


g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

William Pohlhaus

Java Look and Feel

23


g2.setColor(fore);


//draw the text at the x of the textRect and the y textRect plus the font ascent.


//"The font ascent is the distance fr
om the font's baseline to the top of most


//alphanumeric characters."(From Java API Doc on java.awt.FontMetrics.getAscent())


g2.drawString(text,(int)textRect.getX(),(int)textRect.getY()+g2.getFontMetrics().getAscent());


//If there is an icon pa
int it at the x and y of the iconRect


if(b.getIcon()!=null)


b.getIcon().paintIcon(c,g,(int)iconRect.getX(),(int)iconRect.getY());


}

}


William Pohlhaus

Java Look and Feel

24

Appendix D:

Resources

5 really good Resources

1.

A good book on Java Swing preferably one with a chapter or tw
o on look and feel



Java Swing 2nd edition from O’Reilly is what I recommend
and used



ISBN 0
-
596
-
00408
-
7

2.

The Java API Documentation



Always a good resource



http://java.sun.com/apis.html#j2se

3.

The Java base API source code



See what the guys at Sun did



http://j
ava.sun.com/j2se/downloads.html

4.

Someone else’s look and feel source code



See what someone else did, the guys at Sun tend to be more complicated
then need be

5.

Java Developer’s forums



Get help from other developers




http://forum.java.sun.com/