java swing look and feel creation of a look and feel package

56
Java Swing Look and Feel Creation of a Look and Feel package

Upload: clifton-beasley

Post on 12-Jan-2016

265 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Java Swing Look and Feel Creation of a Look and Feel package

Java Swing Look and Feel

Creation of a Look and Feel package

Page 2: Java Swing Look and Feel Creation of a Look and Feel package

Introduction

This presentation is designed to show you how to create a Java Look and Feel for the javax.swing package.

Page 3: Java Swing Look and Feel Creation of a Look and Feel package

Note Before Getting Started

You should have a basic understanding of the Java 2D API java.awt.Graphics and java.awt.Graphics2D classes Shape classes

java.awt.Rectangle, java.awt.image.Arc, etc. Image classes

java.awt.Image, java.awt.images.BufferedImage, etc. java.awt.Font and java.awt.Color

You should have a basic understanding of the Java Swing API The various JComponents (JButton, JPanel, etc)

You are given great freedom in creating your Java look and feel package. Therefore, you should be familiar with other Java look and feel packages so when creating your own it behaves in a similar manner to other Java look and feel packages. javax.swing.plaf.metal look and feel package

Page 4: Java Swing Look and Feel Creation of a Look and Feel package

Resources to Consider

5 really good Resources A good book on Java Swing preferably one with a chapter or two on look

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

ISBN 0-596-00408-7 The Java API Documentation

Always a good resource http://java.sun.com/apis.html#j2se

The Java base API source code See what the guys at Sun did http://java.sun.com/j2se/downloads.html

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 Java Developer’s forums

Get help from other developers http://forum.java.sun.com/

Page 5: Java Swing Look and Feel Creation of a Look and Feel package

Why Bother

Games Current Look and Feels were not designed with games in mind

Marketability Company/Software Logo, Trademark, Distinct Look and Feel

Company Standards for in house applications Quicker Development of Applications

By splitting the look and feel from functionality you can have two different teams developing simultaneously each working on different aspects (functionality and look) at the same time

Easier control of look and feel Rather then setting colors, borders, icons, etc. for each instance of

the swing components you plan on using. Your swing applications might be running on device rather

than a PC

Page 6: Java Swing Look and Feel Creation of a Look and Feel package

How Java Look and Feel Works in a Nutshell

Each Java Swing lightweight class or JComponent has a corresponding user interface class (UI class or ComponentUI) that is responsible for painting the component to the graphical device. These are controlled 100% by the user Java Swing components that do not have a corresponding UI class are the four heavyweight

components: JFrame, JDialog, JWindow, and JApplet. These are controlled by the Operating System and user.

Depending on the OS the user has different levels of control The LookAndFeel class holds meta information about the look and feel

Within the LookAndFeel class the UIDefaults class associates the UI classes, which are created by the look and feel developer, with the Lightweight Java Swing classes they are suppose to paint

The UIManager’s setLookAndFeel methods are used to set which LookAndFeel class is used to associate UI classes with Lightweight Java Swing classes

Once the LookAndFeel class is set any call to paint a Lightweight Java Swing class to the graphical device will use the associated UI class The Lightweight Java Swing class calls the UIManager’s getUI method to fetch the

corresponding UI class The UIManager, which holds a copy of the UIDefaults class from LookAndFeel class, calls

UIDefaults class’s getUI method UIDefaults obtains the UIClassID from the calling Lightweight Java Swing class then it gets the

corresponding UI class through reflection Once the UI class is obtained the UI class’s static createUI method is called which returns an

instance of the UI class The Lightweight Java Swing class then uses the UI class’s paint method when it is asked to

paint or repaint itself See next slide fore detail UML Sequence Diagram

Page 7: Java Swing Look and Feel Creation of a Look and Feel package

Detailed Sequence Diagram of how it works

Marc Loy, Robert Eckstein, Dave Wood, James Elliott and Brain Cole, Java Swing, 2nd, (Sebastopol: O’Reilly, 2003), 1012.

Page 8: Java Swing Look and Feel Creation of a Look and Feel package

Getting Started

Two basic approaches Extending your look and feel from the javax.swing.plaf

package Not recommended if your GUI is to run on a PC

Every UI class is abstract and therefore needs to be extended Extending your Look and Feel from the

javax.swing.plaf.basic package or other look and feel packages Recommended if your GUI is to run on a PC

Has an implementation of every UI class Only need to extend the BasicLookAndFeel class

The approach of extending from the javax.swing.plaf.basic package is basically the same as extending from any other look and feel package

Page 9: Java Swing Look and Feel Creation of a Look and Feel package

UIManager Class

This class is responsible for setting the look and feel

JComponents call this to obtain their corresponding ComponentUI class for the information on how to paint themselves to the graphical device

Page 10: Java Swing Look and Feel Creation of a Look and Feel package

LookAndFeel Class

To start, extend the BasicLookAndFeel class This is the class that is passed into

UIManager.setLookAndFeel method This class is the center of your look and feel

Contains the UIDefaults class Links JComponent classes to ComponentUI classes Lists all the colors, icons, borders, etc. that your look and

feel as available to it Contains all the meta information about your look and

feel

Page 11: Java Swing Look and Feel Creation of a Look and Feel package

LookAndFeel Class Cont.

Abstract Methods to Implement getDescription()

Returns a String describing this look and feel getID()

Returns a String with the ID of this look and feel getName()

Returns a String with the name of this look and feel isNativeLookAndFeel()

Returns a boolean for whether or not this look and feel is native to the operating system it is instantiated on

The Windows look and feel for Java will return true on Window systems and false on all others

Custom look and feels will all always return false isSupportedLookAndFeel()

Returns a boolean for whether or not this look and feel is supported on the operating system it is instantiated on

Cross platform look and feels will usually always return true These methods are used by the UIManager class is a variety of

ways

Page 12: Java Swing Look and Feel Creation of a Look and Feel package

LookAndFeel Class Cont.

Static methods The static methods are provided for convenience

Other methods to consider overriding initialize()

Used for initializing your look and feel Invoked by UIManager before getting the UIDefaults class from the

LookAndFeel class uninitialize()

Used to uninitialize your look and feel Invoked by UIManager before look and feel is replaced by another

look and feel provideErrorFeedback(Component c)

Invoked when the user performs an illegal action “such as pasting into an uneditable JTextField that has focus” – Java API

Page 13: Java Swing Look and Feel Creation of a Look and Feel package

BasicLookAndFeel Class

This is the class to extend when creating your own look and feel By extending the BasicLookAndFeel Class you

get an implementation of every UIClass in the javax.swing.plaf.basic package

Aside from overriding the abstract methods from the LookAndFeel class there are only three methods you need to override to get started

Page 14: Java Swing Look and Feel Creation of a Look and Feel package

BasicLookAndFeel Class cont.

Three methods that give you complete control of your look and feel initSystemColorDefaults(UIDefaults table)

Sets the colors of your look and feel initComponentDefaults(UIDefaults table)

Sets the icons, borders, etc. of your look and feel initClassDefaults(UIDefaults table)

Sets the UI Classes corresponding to the JComponents they are responsible for painting

By overriding these three methods you can customize your look and feel completely

They are called before returning the UIDefaults class to the UIManager class in the getDefaults() method of the BasicLookAndFeel class

Page 15: Java Swing Look and Feel Creation of a Look and Feel package

UIDefaults class

UIDefaults This class holds all the information for your look

and feel The information is stored in key/value pairs The UIManager class retrieves Object values

from the UIDefaults class based on the key pass to one of the many static getXXX(key) methods

Most importantly it holds the Colors, Icons, Borders, Insets, and ComponentUI classes for your look and feel

Page 16: Java Swing Look and Feel Creation of a Look and Feel package

Note about UIDefaults class

A majority of the key/value pairs set by the BasicLookAndFeel in the UIDefaults are only used internally in the look and feel package by the ComponentUI classes This is a good practice to continue because it gives you global control of

your look and feel through one class i.e. If one wants to change the color of the buttons in the look and feel. Then

one can change the value in the UIDefaults class without having to look for it in the button ComponentUI class

The key/value pairs that are used out of the look and feel package are the ones that match JComponent classes to ComponentUI classes

With this in mind two conclusions are drawn One is obligated to set all the key/value pairs for the ComponentUI

classes This is one reason why extending BasicLookAndFeel is a good idea because

these are all set by BasicLookAndFeel Another is that all the Icons, Borders, Colors, etc. are controlled global through

the UIDefaults class by default in BasicLookAndFeel One can add any type of key/value pair to the UIDefaults class to use

Page 17: Java Swing Look and Feel Creation of a Look and Feel package

UIResource interface

This interface is responsible for separating user set colors, borders, insets, etc. from the look and feel’s colors, borders, insets, etc

It has NO methods, it is used to mark objects used by the look and feel from those objects set by the user

This allows the look and feel developer to separate those values set by the user on the JComponent object from those set by the look and feel. This way the look and feel developer won’t override those values when

setting the look and feel or switching to a different look and feel or theme (see javax.swing.plaf.metal look and feel)

Every Icon, Inset, Border, ComponentUI class, etc. for the look and feel will have to or already has implemented this interface

There are also several convenience classes that implement this interface that are useful ColorUIResource, BorderUIResource, InsetUIResource, etc.

Page 18: Java Swing Look and Feel Creation of a Look and Feel package

Adding key/value pairs to the UIDefaults class

To add key/values the UIDefaults to first create an Object[] that is the twice the length of the amount of key/value pairs you want to add If you are adding 12 key/value pairs the length of the

Object[] is 24 Add your key/value pairs to the Object[] by setting

the first key to the Object[] at index 0 followed by it’s value at index 1 continue with the next key/value pair at index 2 and 3, continue until the Object[] is full

Then call the UIDefaults method putDefaults(Object[] obj) and pass the Object[] to it.

Page 19: Java Swing Look and Feel Creation of a Look and Feel package

Code Example of adding Key/Value pairs to UIDefaults

/* Adding two key values to table */UIDefaults table …Object[] key_values = new Object[4]; key_values[0] = “desktop”; // 1st keykey_values[1] = “#FFFFFF”; // 1st key’s valuekey_values[2] = “Button.margin”; // 2nd keykey_values[3] = new InsetsUIResource(1,1,1,1); // 2nd key’s valuetable.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);

Page 20: Java Swing Look and Feel Creation of a Look and Feel package

Setting System Colors

Override the initSystemColorDefaults(UIDefaults table) System Colors

Every color used by the BasicLookAndFeel’s UI classes is set by default to one of the System Colors

This givens one global control of all the colors in the look and feel

Overriding the method Two primary ways

One Setting every System Colors’ key/value pair with

ColorUIResource Objects Passing the Object[] holding them in the UIDefaults table

Two Setting some or all the System Colors’ key/value pairs

using String representations for the color values Passing the UIDefaults class, the Object[] with the

key/value pairs to the loadSystemColors method

Page 21: Java Swing Look and Feel Creation of a Look and Feel package

System colors

These are the System colors that the BasicLookAndFeel uses 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) window 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 controlDkShadowDark shadow color for controls scrollbar Scrollbar background (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 Code for javax.swing.plaf.basic.BasicLookAndFeel Sun Mircosystems Inc.

Page 22: Java Swing Look and Feel Creation of a Look and Feel package

Example Code for Overriding initSystemColorDefaults(UIDefaults table)

//By setting every System color key protected void initSystemColorDefaults(UIDefaults table) { ColorUIResource pr1 = new ColorUIResource(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 = new 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 borders. */ "inactiveCaption" , 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) window 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 background color when selected */ "textHighlightText" , wht, /* Text color when selected */ "textInactiveText" , gry, /* Text color when disabled */ "control" , pr1, /* Default color for controls (buttons, sliders, etc) */ "controlText" , blk, /* Default color for text in controls (buttons, sliders, etc) */ "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 */ "scrollbar" , pr3, /* Scrollbar background (usually the "track") */ "info" , wht, /* Background color for informational text */ "infoText" , blk /* Color for informational text */ }; table.putDefaults(colors); }

Page 23: Java Swing Look and Feel Creation of a Look and Feel package

Example Code for Overriding initSystemColorDefaults(UIDefaults table)

/*By setting only sum and using String representations of the colors */

protected void initSystemColorDefaults(UIDefaults table) { Object[] colors = { "desktop“, “#CC5500”, "activeCaption“, “#FFFFFF”,

"activeCaptionText“, “#000000” }; loadSystemColors(table, colors, false); /* the last value false is saying not to override your changes with the native system colors */ }

Page 24: Java Swing Look and Feel Creation of a Look and Feel package

Setting Components

Override the initComponentDefaults(UIDefaults table) Components are various objects used by the UI classes

Borders, Insets, Fonts, Colors, etc By default all the color components are mapped to one of the System Colors

By convention the keys are named by the ComponetUI class that is going to use it i.e. key “button.border” would be the border component used by the

ComponentUI button class See Java Swing 2nd Edition by O’Reilly Appendix A for a complete list of

all the components set by the BasicLookAndFeel Overriding the method

Call the super.initComponentDefaults(UIDefaults table) method (unless you map all the components) This will map all the component key/value pairs from the BasicLookAndFeel Note this is not done in initSystemColorDefaults(UIDefaults table);

Set the key/value pairs that are to be changed Pass the Object[] holding the key/value pairs to the

UIDefaults.putDefaults(Object[] obj) method

Page 25: Java Swing Look and Feel Creation of a Look and Feel package

Example Code for Overriding initComponentDefaults(UIDefaults table)

protected void initComponentDefaults(UIDefaults table) { super.initComponentDefaults(table); Object[] components = { "CheckBox.icon", new CheckBoxIcon(), "Button.background",pr4, "Button.foreground",wht, "Button.font", new Font("Times",Font.BOLD|Font.ITALIC,10) }; table.putDefaults(components); }

Page 26: Java Swing Look and Feel Creation of a Look and Feel package

Setting ComponentUI Classes

Override the initClassDefaults(UIDefaults table) ComponentUI Classes are the classes responsible for painting the varies

JComponents The keys to the ComponentUI class must match what is returned by the

JComponent’s getUIClassID() method for the class they are to paint The convention is: the name of the JComponent minus the processing J and adding UI at

the end i.e. JButton.getUIClassID() returns the String “ButtonUI” and therefore the key for the UI class must be

the String“ButtonUI” The values must be a String object holding the complete name of the

ComponentUI class (this is the package+class name) i.e. “william.swing.plaf.blue.BlueButtonUI”

The package is william.swing.plaf.blue The class is BlueButtonUI

Overriding the method Call the super.initClassDefaults(UIDefaults table) method (unless you map all the

ComponentUI classes) This will map all the UI classes key/value pairs from the BasicLookAndFeel Note this is not done in initSystemColorDefaults(UIDefaults table);

Set the key/value pairs that are to be changed Pass the Object[] holding the key/value pairs to the UIDefaults.putDefaults(Object[] obj)

method

Page 27: Java Swing Look and Feel Creation of a Look and Feel package

Example Code for Overriding initClassDefaults(UIDefaults table)

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

Page 28: Java Swing Look and Feel Creation of a Look and Feel package

ComponentUI Classes

These are the classes responsible for painting the JComponents to the graphical device Each ComponentUI class is responsible for painting one

of the JComponents They all extend ComponentUI class The convention for naming the ComponentUI

Classes is the short name of the look and feel + UIClassID of the JComponent the ComponentUI is to paint i.e. BlueButtonUI (Blue + ButtonUI) is responsible for for

painting JButton which returns ButtonUI as its UIClassID

Page 29: Java Swing Look and Feel Creation of a Look and Feel package

ComponentUI methods

public static ComponentUI createUI(JComponent c) The factory method that creates the UI class Two options

One: create a singleton How

By returning a static class variable of the ComponentUI class Pros

Uses less memory because there is only one instance of the ComponentUI class that is responsible for painting

Cons No stateful information can be held for a particle JComponent but rather all the JComponets that

ComponentUI class is painting for will share the same state Two: create a new instance

How By returning a new instance

Pros Stateful information may be held by the ComponentUI class of a particle JComponent and can

share state through static class variables Cons

Uses more memory because each JComponent that needs this ComponentUI class will have an instance of it

How to decide More often then not you will use a singleton because any stateful information can be stored in the

JComponent itself When the stateful information can not be stored in the JComponent and is critical to the look and feel for

that JComponent If extending the Basic Look And Feel this must be overridden and return an

instance, singleton or new, of the ComponentUI this method is a member of If not, then the Basic Look And Feel instance will be returned

Page 30: Java Swing Look and Feel Creation of a Look and Feel package

Example of createUI method

//From william.swing.plaf.blue.BlueButtonUI //which is responible for painting JButtons

//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(); }

Page 31: Java Swing Look and Feel Creation of a Look and Feel package

ComponentUI methods cont.

public void installUI(JComponent c) Install default components (Color, Borders, etc.)

Set the components on the JComponent if the user has not set them To check if the user has set a component or not

Get it from the JComponent Test if it is an instance of UIResourse If it is not a UIResourse then the user set this value

If it is not a UIResourse the convention is to leave what the user has set

If it is a UIResourse Set the component to what the value is in the UIDefaults table Use the UIManager to get values from the UIDefaults table

Examples of methods that set component state from JMenu setForeground(Color fg) setBackground(Color bg)

The JComponent holds the various states of the components for painting itself Install listeners

Listeners are responsible for setting the state of the JComponent through the varies setters and getters in the JComponent i.e. on a mouse Pressed event of a JButton the listener will set the JButton’s pressed class variable to true

through setPressed(boolean p) method Install Keyboard Actions

Registers keyboard actions to set state of the JComponent i.e. registering the spacebar to be the same as the left mouse click

Install anything else you may need More often then not this method won’t be overridden if you are extending the Basic Look And

Feel UI class Called by JComponent when the JComponent calls setUI(ComponentUI ui) Typically the JComponent c is casted to an object of the actual class that is to be painted

i.e. if the ComponentUI class is to paint a JSeparator then cast c to a Jseparator object

Page 32: Java Swing Look and Feel Creation of a Look and Feel package

Example of installUI method

//From william.swing.plaf.blue.BlueButtonUI which is responible for painting JButtons

public void installUI(JComponent c) { /*Casting the JComponent c to AbstractButton b (several Lightweight Java Swing class extend

AbstractButton)*/ AbstractButton b = (AbstractButton)c; /*Setting the default components for the JButton Getting the default font, background color and foreground color from the UIDefaults table

for buttons*/ background = UIManager.getColor("Button.background"); foreground = UIManager.getColor("Button.foreground"); font = UIManager.getFont("Button.font");

/*Setting background and foreground colors on the JComponent c if the user did NOT set them These values can be retrieved later by the paint method through c*/ if(c.getBackground()==null || (c.getBackground() instanceof 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*/ }

Page 33: Java Swing Look and Feel Creation of a Look and Feel package

ComponentUI methods cont.

public void uninstallUI(JComponent c) Used to remove and cleanup

Listeners Keyboard Actions Components Anything else

More often then not this method won’t be overridden if you are extending the Basic Look And Feel UI class

Called by JComponent when the JComponent calls setUI(ComponentUI ui) if and only if the JComponent previously had a set it’s UI class

Page 34: Java Swing Look and Feel Creation of a Look and Feel package

Example of uninstallUI method

//From javax.swing.plaf.basic.BasicButtonUI

public void uninstallUI(JComponent c) { //Uninstalling keyboard registations uninstallKeyboardActions((AbstractButton)

c); //Uninstalling listeners uninstallListeners((AbstractButton) c); //Uninstalling default components uninstallDefaults((AbstractButton) c); }

Page 35: Java Swing Look and Feel Creation of a Look and Feel package

ComponentUI methods cont.

Sizing methods Three sizing methods

getMinimumSize() getMaximumSize() getPreferredSize()

Used by various Layout Managers to get the size of the Graphics object for the JComponent Some will ignore these values

i.e. GridLayout and BorderLayout

Page 36: Java Swing Look and Feel Creation of a Look and Feel package

ComponentUI methods cont.

public void paint(Graphics g, JComponent c) This method is responsible for painting the JComponent to

the graphical device Most of the work will be done here Graphical state and function state information is obtained

from the JComponent Examples of Graphical states

Foreground color Background color Borders

Examples of Function states Is the button pressed

The Graphics object is really a Graphics2D object

Page 37: Java Swing Look and Feel Creation of a Look and Feel package

Example of paint method

//Example of painting semi-translucent lines on a MenuBar

public void paint(Graphics g, JComponent c) { super.paint(g, c);

//Get the state of the background color from the JComponent Color bg = c.getBackground().darker().darker(); g.setColor(new Color(bg.getRed(),bg.getGreen(),bg.getBlue(),127));

/*Added lines at every 5 pixels of 1 pixel height and the width of the JMenuBar

Note the getting of the width and height from the JMenuBar and that the Graphic starts at 0,0*/

for(int j=0;j<c.getHeight();) { g.fillRect(0,j,c.getWidth(),1); j=j+5; } }

Page 38: Java Swing Look and Feel Creation of a Look and Feel package

Non-ComponentUI methods

If you are extending the Basic look and feel you will have various methods available to use depending on the UI Class.

Page 39: Java Swing Look and Feel Creation of a Look and Feel package

3 Ways to Control Look and Feel

With the preceding covered, 3 ways of controlling look and feel should become evident by extending the javax.swing.plaf.basic look and feel package Through color Through components Through CompnentUI classes

Page 40: Java Swing Look and Feel Creation of a Look and Feel package

Through Color

This is the simplest of the three methods Override the

initSystemColorDefaults(UIDefaults table) method Set the System colors as desired

With a little trial and error one can see quickly what System colors control what components

Page 41: Java Swing Look and Feel Creation of a Look and Feel package

Through Components

This is a bit harder than through colors but gives greater control

Override the initComponentDefaults(UIDefaults table) method Set icons, borders, insets, etc. as desired

Creating your own components Become familiar with the component you are going to create It is easiest to create a factory 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) All types of a component are centrally located in one class

so the management is easier i.e. all your borders will be inner classes of and created by

your border factory class

Page 42: Java Swing Look and Feel Creation of a Look and Feel package

Example of a Checkbox Icon Component cont.package william.swing.plaf.blue;

import java.awt.*;import java.io.Serializable;import java.net.URL;import javax.swing.*;

//I could have implemented javax.swing.plaf.IconUIResourcepublic class CheckBoxIcon implements UIResource, Icon, Serializable {

//two images to represent the checkbox being unchecked and checked Image unchecked = null, checked = null; //the size of this icon int width = 20, height = 20;

//the constructor is loading the images public CheckBoxIcon() { unchecked = new

ImageIcon(this.getClass().getResource("/william/swing/plaf/blue/unchecked.gif")).getImage(); checked = new

ImageIcon(this.getClass().getResource("/william/swing/plaf/blue/checked.gif")).getImage(); }

public int getIconWidth() { return width; }

public int getIconHeight() { return height; }

Page 43: Java Swing Look and Feel Creation of a Look and Feel package

Example of a Checkbox Icon Component cont. /*c is the checkbox, g is the Graphics object from the paint method of the CheckboxUI class x and y are where the icon is to be painted on the Graphics object g */ public void paintIcon(Component c, Graphics g, int x, int y) { /*This icon will be used with a JCheckBox so the assumption can be made to cast it as an AbstractButton will provide state information of the checkbox */ ButtonModel model = ((AbstractButton)c).getModel(); //This ant aliasing provides a nice blended into the background ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,

RenderingHints.VALUE_ANTIALIAS_ON); //Drawing the unchecked image by default at x and y g.drawImage(unchecked,x,y,width,height,null); //If the checkbox is checked then paint over the unchecked image with the checked image if(model.isSelected()||model.isPressed()||model.isArmed()) g.drawImage(checked,x,y,width,height,null); //Drawing a 2px circle around the checkbox g.drawOval(x+1,y+1,width-1,height-1); g.drawOval(x,y,width,height); }}

Page 44: Java Swing Look and Feel Creation of a Look and Feel package

Example of a Checkbox Icon Component cont.

//Then you just add it to the UIDefaults table

protected void initComponentDefaults(UIDefaults table) { super.initComponentDefaults(table); Object[] components = { "CheckBox.icon", new CheckBoxIcon() }; table.putDefaults(components); }

The checkbox goes from this:

To this:

It should be noted that this would be better as a radio button then a check box due to its round nature

Page 45: Java Swing Look and Feel Creation of a Look and Feel package

Example of a Checkbox Icon Component cont.

Two notes about using images One

One 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 This way one can store all images within the look and

feel package for that look and feel Two

By using the javax.swing.ImageIcon class for retrieving Images one is guaranteed the image will be loaded in the Image object when getImage() method is called This is easier and safer than use the DefaultToolkit from

the java.awt.Toolkit class for loading images

Page 46: Java Swing Look and Feel Creation of a Look and Feel package

Through ComponentUI Classes

This is the hardest but gives the greatest control Override the initClassDefaults (UIDefaults table) method The example is of ComponentUI responsible for painting

JButton It is good to understand this because of the 40 or so

JComponents 8 are buttons and behave very similarly to JButton This example shows how one has to do the following

Painting the button Painting the text if there is text Painting the icon if there is an icon Setting up the listeners Determining user values look and feel set values A singleton

Page 47: Java Swing Look and Feel Creation of a Look and Feel package

Example of a Button ComponentUI

package william.swing.plaf.blue;

import java.awt.*;import java.awt.image.*;import javax.swing.*;import java.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(); //Default 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 createUI(JComponent c) { return b; }

Page 48: Java Swing Look and Feel Creation of a Look and Feel package

Example of a Button ComponentUI cont.

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 them //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() instanceof 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*/ }

Page 49: Java Swing Look and Feel Creation of a Look and Feel package

Example of a Button ComponentUI cont.

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

public void paint(Graphics g, JComponent c) { //Once 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 Graphics2D 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.getInsets(); //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)); //the area that the text will be drawn 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.getFontMetrics(), b.getText(), b.getIcon(), b.getVerticalAlignment(), b.getHorizontalAlignment(), b.getVerticalTextPosition(), b.getHorizontalTextPosition(), viewRect, iconRect, textRect,

b.getText() == null ? 0 : b.getIconTextGap());

Page 50: Java Swing Look and Feel Creation of a Look and Feel package

Example of a Button ComponentUI cont.

//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 BufferedImage(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 = new 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.setColor(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.getWidth(),2); j=j+4; }

Page 51: Java Swing Look and Feel Creation of a Look and Feel package

Example of a Button ComponentUI cont.

//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, RenderingHints.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(ar1); 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 text g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 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 from 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 paint it at the x and y of the iconRect if(b.getIcon()!=null) b.getIcon().paintIcon(c,g,(int)iconRect.getX(),(int)iconRect.getY()); }

Page 52: Java Swing Look and Feel Creation of a Look and Feel package

Example of a Button ComponentUI cont.

//Then you just add it to the UIDefaults table protected void initClassDefaults(UIDefaults table) { super.initClassDefaults(table); //package that the ComponentUI classes belong too String pkg = "william.swing.plaf.blue."; Object[] classes = {

"ButtonUI" , pkg + "BlueButtonUI" }; table.putDefaults(classes); }}

Page 53: Java Swing Look and Feel Creation of a Look and Feel package

Last Note on ComponentUI

Each ComponentUI is slightly different, though there are strong similarities between many of them (i.e. buttons, panels, etc.), and only through trial and error and reviewing the source code of the Java API or someone else’s look and feel will you be able to fully master each ComponentUI

Page 54: Java Swing Look and Feel Creation of a Look and Feel package

Future Research

Active and Lazy Values GTK+ for Java 1.4 How motion is achieved

Page 55: Java Swing Look and Feel Creation of a Look and Feel package

Glossary for this Presentation

Component Any object or class that is use to help create the look and feel

ComponentUI Parent class of all UI classes; any UI class (see UI Class)

Factory Class A class whose sole purpose it to return instances of classes through factory methods

Factory method A static method that is responsible for returning and instance of a class, whether it be a singleton

or new instance Heavyweight Java Swing Class

Top level swing classes; painting is partly or completely controlled by the OS JComponent

Parent class of Lightweight Java Swing classes; any Lightweight Java Swing class (see Lightweight Java Swing Class)

Lightweight Java Swing Class A Swing class that allows for pluggable look and feel through UIManager.setLookAndFeel

Singleton An instance of a class in which there will be only one instance within of it within the JVM

UI Class A class that is responsible for paint a JComponent class

Page 56: Java Swing Look and Feel Creation of a Look and Feel package

Author

By William Pohlhaus Email:

[email protected] Homepage:

http://www.homepage.villanova.edu/william.pohlhaus