JMU
Customizing Components in Java
An Introduction


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Introduction
Themes
Themes (cont.)

Creating a Theme

  1. Create a class that extends DefaultMetalTheme
  2. Override the desired accessor methods
javaexamples/lookandfeel/JMUTheme.java
        package lookandfeel;

import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.metal.*;

/**
 * A theme for the Java Look-And-Feel that is in JMU
 * colors.
 */
public class JMUTheme extends DefaultMetalTheme
{
    private ColorUIResource  gold       = new ColorUIResource(194,161, 77);
    private ColorUIResource  darkGold   = new ColorUIResource(143,118, 50);  
    private ColorUIResource  lightGold  = new ColorUIResource(214,192,135);  
    private ColorUIResource  paleGold   = new ColorUIResource(252,246,228);
    private ColorUIResource  purple     = new ColorUIResource( 69,  0,132);
    private ColorUIResource  palePurple = new ColorUIResource(214,168,255);




    /**
     * The color to use for white areas 
     * (e.g., the background of a JTextArea)
     */
    public ColorUIResource getWhite()
    {
        return paleGold;
    }


    /**
     * The color to use for things like the border of tool tips
     */
    protected ColorUIResource getPrimary1() 
    { 
        return purple; 
    }

    /**
     * The color to use for things like the border of text highlighting
     */
    protected ColorUIResource getPrimary2() 
    { 
        return purple; 
    }

    /**
     * The color to use for things like text highlighting and the background
     * of tool tips
     */
    protected ColorUIResource getPrimary3() 
    { 
        return palePurple; 
    }
    
    /**
     * The color to use for things like the light line in etched borders
     */
    protected ColorUIResource getSecondary1() 
    { 
        return lightGold; 
    }

    /**
     * The color to use for things like buttons (when pressed)
     */
    protected ColorUIResource getSecondary2() 
    { 
        return darkGold; 
    }

    /**
     * The color to use for things like component backgrounds
     */
    protected ColorUIResource getSecondary3() 
    { 
        return gold; 
    }


    /**
     * The font to use for conrol text
     */
    public FontUIResource getControlTextFont()
    {
        return new FontUIResource("Serif", Font.BOLD, 14);
    }

    /**
     * The font to use for menu text
     */
    public FontUIResource getMenuTextFont()
    {
        return new FontUIResource("Serif", Font.BOLD, 14);
    }

    /**
     * The font to use for sub text
     */
    public FontUIResource getSubTextFont()
    {
        return new FontUIResource("Serif", Font.PLAIN, 12);
    }

    /**
     * The font to use for system text (e.g., in tool tips)
     */
    public FontUIResource getSystemTextFont()
    {
        return new FontUIResource("Sans Serif", Font.PLAIN, 10);
    }

    /**
     * The font to use for user text (e.g., in text components)
     */
    public FontUIResource getUserTextFont()
    {
        return new FontUIResource("Serif", Font.PLAIN, 14);
    }

    /**
     * The font to use for window title text
     */
    public FontUIResource getWindowTitleTextFont()
    {
        return new FontUIResource("Serif", Font.PLAIN, 16);
    }
}
        
Themes (cont.)

Using a Theme

  1. Construct an instance of the theme
  2. Call the static setCurrentTheme method in the MetalLookAndFeel class
javaexamples/lookandfeel/ThemeDemo.java
        package lookandfeel;

import java.awt.*;
import java.io.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.metal.*;

import gui.*;

/**
 * An example that illustrates the use of themes
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison University
 */
public class ThemeDemo
{

    /**
     * The entry point
     */
    public static void main(String[] args)
    {
        CloseableFrame               f;
        JComponent                   contentPane;
        JListEditor                  jle;
        JMUTheme                     theme;


        f = new CloseableFrame();

        // Set the theme
        theme = new JMUTheme();
        MetalLookAndFeel.setCurrentTheme(theme);
        


        // Re-load the look-and-feel
        try {

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

        } catch (ClassNotFoundException cnfe) {
            
            System.out.println("Couldn't set look and feel");
            
        } catch (InstantiationException ie) {
            
            System.out.println("Couldn't set look and feel");
            
        } catch (IllegalAccessException ie) {
            
            System.out.println("Couldn't set look and feel");
            
        } catch (UnsupportedLookAndFeelException ie) {
            
            System.out.println("Couldn't set look and feel");
        }


        contentPane = (JComponent)(f.getContentPane());
        contentPane.setLayout(new BorderLayout());

        jle = new JListEditor();
        contentPane.add(jle, BorderLayout.CENTER);
        SwingUtilities.updateComponentTreeUI(f);

        f.setSize(400,300);
        f.setVisible(true);

    }
}
        
Client Properties
Client Properties (cont.)
Swapping Views between Components
Swapping Views between Components (cont.)

Make a JTextArea look like a JLabel

javaexamples/gui/WrappingLabel.java
        package gui;

import java.awt.*;
import javax.swing.*;

/**
 * A component that contains text.  This component is slightly
 * more versatile than a JLabel because it wraps at word
 * boundaries.
 *
 * @version 1.0
 * @author  Prof. David Bernstein
 */
public class WrappingLabel extends JTextArea
{

    /**
     * Default constructor
     */
    public WrappingLabel()
    {
        this("");
    }



    /**
     * Explicit Value Constructor
     *
     * @param text   The text on the label
     */
    public WrappingLabel(String text)
    {
        super(text);


        // Set the wrapping behavior
        setLineWrap(true);
        setWrapStyleWord(true);

        // Make this TextComponent behave like a Lavel
        setEditable(false);
        setHighlighter(null);
    }




    /**
     * Reloads the pluggable UI. 
     */
    public void updateUI()
    {
        super.updateUI();

        // Change the border (to the one used by Label objects)
        LookAndFeel.installBorder(this, "Label.border");

        // Change the background color, foreground color,
        // and font (to those used by Label objects)
        LookAndFeel.installColorsAndFont(this,
                                        "Label.background",
                                        "Label.foreground",
                                        "Label.font"
                                        );
    }
}
        
Swapping Views between Components (cont.)

What exists and what can be changed?

javaexamples/lookandfeel/ShowUIDefaults.java
        import java.util.*;
import javax.swing.*;

/**
 * Show the name-value pairs associated with views
 *
 * @author  Prof. David Benrstein, James Madison University
 * @version 1.0
 */
public class ShowUIDefaults
{
    /**
     * The entry point
     */
    public static void main(String[] args)
    {
       Enumeration       e;
       int               i;
       String[]          keys;
       UIDefaults        defaults;


       defaults = UIManager.getDefaults();
       keys = new String[defaults.size()];

       e = defaults.keys();
       i = 0;
       while (e.hasMoreElements()) 
       {
          keys[i] = e.nextElement().toString();
          i++;
       }


       Arrays.sort(keys);
       for (i=0; i < keys.length; i++) 
       {
          System.out.println(keys[i]+"\t"+defaults.get(keys[i]));
       }
    }

}
        
Adding Capabilities to a View
Adding Capabilities to a View

An Example

javaexamples/lookandfeel/AudioButtonUI.java
        package lookandfeel;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.*;

/**
 * A view for a JButton with (limited) audio
 *
 * @author  Prof. David Benrstein, James Madison University
 * @version 1.0
 */
public class AudioButtonUI extends    ComponentUI
                           implements MouseListener
{
    private static AudioButtonUI instance = new AudioButtonUI();
    private static Toolkit       toolkit = Toolkit.getDefaultToolkit();



    /**
     * Create the view (required)
     */
    public static ComponentUI createUI(JComponent c)
    {
        return instance;
    }



    /**
     * Install the view on the given JComponent
     *
     * @param c   The JComponent
     */
    public void installUI(JComponent c)
    {
        c.addMouseListener(instance);
    }


    /**
     * Handle mouseClicked events (required by MouseListener)
     *
     * @param evt   The MouseEvent
     */
    public void mouseClicked(MouseEvent evt)
    {
    }




    /**
     * Handle mouseEntered events (required by MouseListener)
     *
     * @param evt   The MouseEvent
     */
    public void mouseEntered(MouseEvent evt)
    {
        Component        source;

        source = (Component)(evt.getSource());
        if (source.isEnabled()) toolkit.beep();
    }





    /**
     * Handle mouseExited events (required by MouseListener)
     *
     * @param evt   The MouseEvent
     */
    public void mouseExited(MouseEvent evt)
    {
    }



    /**
     * Handle mousePressed events (required by MouseListener)
     *
     * @param evt   The MouseEvent
     */
    public void mousePressed(MouseEvent evt)
    {
    }



    /**
     * Handle mouseReleased events (required by MouseListener)
     *
     * @param evt   The MouseEvent
     */
    public void mouseReleased(MouseEvent evt)
    {
    }






    /**
     * Uninstall the view from the given JComponent
     *
     * @param c   The JComponent
     */
    public void uninstallUI(JComponent c)
    {
        c.removeMouseListener(instance);
    }




    /**
     * Update this component
     *
     * Specifically, do nothing.  (The default implementation
     * will clear the component's background.)
     */
    public void update(Graphics g, JComponent c)
    {

    }
}
        
javaexamples/lookandfeel/AudioLookAndFeel.java
        package lookandfeel;

import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.metal.*;

/**
 * A LookAndFeel with (limited) audio
 *
 * @author  Prof. David Benrstein, James Madison University
 * @version 1.0
 */
public class AudioLookAndFeel extends MetalLookAndFeel
{
    private static final String description = "A LookAndFeel with audio";
    private static final String id          = "edu.jmu.cs.bernstdh.AudioLF";
    private static final String name        = "Audio LookAndFeel";



    /**
     * Get the UI Defaults for this LookAndFeel
     */
    public UIDefaults getDefaults()
    {
        Object[]         nvPair = {"ButtonUI","lookandfeel.AudioButtonUI"};
        UIDefaults       defaults;


        // Get the "normal" defaults
        defaults = super.getDefaults();

        // Add the new default and fire a PropertyChangeEvent
        defaults.putDefaults(nvPair);

        return defaults;
    }



    /**
     * Get the long description
     */
    public String getDescription()
    {
        return description;
    }


    /**
     * Get the String identifier
     */
    public String getID()
    {
        return id;
    }

    /**
     * Get the name
     */
    public String getName()
    {
        return name;
    }



    /**
     * Is this LF native to the OS?
     */
    public boolean isNativeLookAndFeel()
    {
        return false;
    }


    /**
     * Is this LF supported on this OS?
     */
    public boolean isSupportedLookAndFeel()
    {
        return true;
    }
}
        
javaexamples/lookandfeel/AudioLFDemo.java
        package lookandfeel;

import java.applet.*;
import java.awt.*;
import java.io.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.metal.*;

import gui.*;

/**
 * An example that illustrates the AudioLookAndFeel
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison University
 */
public class AudioLFDemo
{

    /**
     * The entry point
     */
    public static void main(String[] args)
    {
        AudioLookAndFeel             audioLF;
        CloseableFrame               f;
        JComponent                   contentPane;
        JListEditor                  jle;

        audioLF = new AudioLookAndFeel();
        UIManager.addAuxiliaryLookAndFeel(audioLF);
        
        f = new CloseableFrame();
        contentPane = (JComponent)(f.getContentPane());
        contentPane.setLayout(new BorderLayout());
        
        
        jle = new JListEditor();
        contentPane.add(jle, BorderLayout.CENTER);
        
        f.setSize(400,300);
        f.setVisible(true);
        
    }
}
        
Building a View for One (or a Few) Widgets

An Example

javaexamples/lookandfeel/JMUSliderUI.java
        package lookandfeel;

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.basic.*;
import javax.swing.plaf.metal.*;

/**
 * A slider that uses the JMU Cupola for its "thumb"
 *
 * @author  Prof. David Benrstein, James Madison University
 * @version 1.0
 */
public class JMUSliderUI extends BasicSliderUI
{
    private BoundedRangeModel    model;
    private Image                cupola;


    /**
     * Explicit Value Constructor
     */
    public JMUSliderUI(JSlider slider)
    {
        super(slider);
        ImageIcon     icon;

        this.slider = slider;
        this.model  = slider.getModel();

        icon   = new ImageIcon("cupola_tiny.gif");
        cupola = icon.getImage();

        System.out.println("JMUSliderUI Constructor");
        
    }
    

    
    /**
     * Create the view
     */
    public static ComponentUI createUI(JComponent c)
    {
        // Return a new UI delegate since it may not
        // be stateless.  This may be changed later.
        return new JMUSliderUI((JSlider)c);
    }




    /**
     * Paint the "thumb" of the slider
     *
     * @param g   The RenderingEngine
     */
    public void paintThumb(Graphics g)
    {
        Graphics2D       g2;

        g2 = (Graphics2D)g;
        g.drawImage(cupola, thumbRect.x, thumbRect.y, null);
    }

}
        
javaexamples/lookandfeel/JMULookAndFeel.java
        package lookandfeel;

import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.metal.*;


/**
 * A (partial) LookAndFeel that uses JMU visuals
 *
 * @author  Prof. David Benrstein, James Madison University
 * @version 1.0
 */
public class JMULookAndFeel extends MetalLookAndFeel
{
    private static final String description = "A LookAndFeel for JMU";
    private static final String id          = "edu.jmu.cs.bernstdh.JMULF";
    private static final String name        = "JMU LookAndFeel";



    /**
     * Get the long description
     */
    public String getDescription()
    {
        return description;
    }


    /**
     * Get the String identifier
     */
    public String getID()
    {
        return id;
    }

    /**
     * Get the name
     */
    public String getName()
    {
        return name;
    }


    /**
     * Initialize the defaults 
     */
    protected void initClassDefaults(UIDefaults table) 
    {
        String       packageName;
        
        super.initClassDefaults(table);
        packageName = "lookandfeel";
        
        table.put("SliderUI", packageName+".JMUSliderUI");
    }
}
        
javaexamples/lookandfeel/JMULAFDemo.java