Java/Swing Components/Panel

Материал из Java эксперт
Перейти к: навигация, поиск

A basic panel that displays a small up or down arrow.

  
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 * 
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 * 
 * ---------------
 * ArrowPanel.java
 * ---------------
 * (C) Copyright 2002-2004, by Object Refinery Limited.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: ArrowPanel.java,v 1.6 2007/11/02 17:50:36 taqua Exp $
 *
 * Changes
 * -------
 * 25-Sep-2002 : Version 1 (DG);
 * 13-Oct-2002 : Added Javadocs (DG);
 *
 */
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;
/**
 * A basic panel that displays a small up or down arrow.
 * 
 * @author David Gilbert
 */
public class ArrowPanel extends JPanel {
  /** A constant for the up arrow. */
  public static final int UP = 0;
  /** A constant for the down arrow. */
  public static final int DOWN = 1;
  /** The arrow type. */
  private int type = UP;
  /** The available area. */
  private Rectangle2D available = new Rectangle2D.Float();
  /**
   * Creates a new arrow panel.
   * 
   * @param type
   *          the arrow type.
   */
  public ArrowPanel(final int type) {
    this.type = type;
    setPreferredSize(new Dimension(14, 9));
  }
  /**
   * Paints the arrow panel.
   * 
   * @param g
   *          the graphics device for drawing on.
   */
  public void paintComponent(final Graphics g) {
    super.paintComponent(g);
    final Graphics2D g2 = (Graphics2D) g;
    // first determine the size of the drawing area...
    final Dimension size = getSize();
    final Insets insets = getInsets();
    this.available.setRect(insets.left, insets.top, size.getWidth() - insets.left - insets.right,
        size.getHeight() - insets.top - insets.bottom);
    g2.translate(insets.left, insets.top);
    g2.fill(getArrow(this.type));
  }
  /**
   * Returns a shape for the arrow.
   * 
   * @param t
   *          the arrow type.
   * 
   * @return the arrow shape.
   */
  private Shape getArrow(final int t) {
    switch (t) {
    case UP:
      return getUpArrow();
    case DOWN:
      return getDownArrow();
    default:
      return getUpArrow();
    }
  }
  /**
   * Returns an up arrow.
   * 
   * @return an up arrow.
   */
  private Shape getUpArrow() {
    final Polygon result = new Polygon();
    result.addPoint(7, 2);
    result.addPoint(2, 7);
    result.addPoint(12, 7);
    return result;
  }
  /**
   * Returns a down arrow.
   * 
   * @return a down arrow.
   */
  private Shape getDownArrow() {
    final Polygon result = new Polygon();
    result.addPoint(7, 7);
    result.addPoint(2, 2);
    result.addPoint(12, 2);
    return result;
  }
}





A JPanel with a textured background.

  
/*
 *  TexturedPanel.java
 *  2006-11-02
 */
//cb.aloe.decor;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import javax.swing.Icon;
import javax.swing.JPanel;
/**
 * A JPanel with a textured background.
 * 
 * @author Christopher Bach
 */
public class TexturedPanel extends JPanel {
  private TexturePaint ourPainter = null;
  private Color ourDefaultForeground = Color.white;
  private Color ourDefaultBackground = Color.gray;
  /**
   * Creates a new TexturedPanel with a simple striped pattern.
   */
  public TexturedPanel() {
    super();
    ourDefaultForeground = Color.white;
    ourDefaultBackground = getBackground();
    setupDefaultPainter(ourDefaultForeground, ourDefaultBackground);
  }
  /**
   * Creates a new TexturedPanel with a simple striped pattern consisting of the
   * given foreground and background colors.
   */
  public TexturedPanel(Color foreground, Color background) {
    super();
    ourDefaultForeground = (foreground != null ? foreground : Color.white);
    ourDefaultBackground = (background != null ? background : getBackground());
    setupDefaultPainter(ourDefaultForeground, ourDefaultBackground);
  }
  /**
   * Creates a new TexturedPanel with a simple pattern based on the provided
   * texture map and consisting of the given foreground and background colors.
   */
  public TexturedPanel(Color foreground, Color background, boolean[][] texture) {
    super();
    ourDefaultForeground = (foreground != null ? foreground : Color.white);
    ourDefaultBackground = (background != null ? background : getBackground());
    setupTexturePainter(ourDefaultForeground, ourDefaultBackground, texture, 1);
  }
  /**
   * Creates a new TexturedPanel with a simple pattern based on the provided
   * texture map and consisting of the given foreground and background colors.
   */
  public TexturedPanel(Color foreground, Color background, boolean[][] texture, int scale) {
    super();
    ourDefaultForeground = (foreground != null ? foreground : Color.white);
    ourDefaultBackground = (background != null ? background : getBackground());
    setupTexturePainter(ourDefaultForeground, ourDefaultBackground, texture, scale);
  }
  /**
   * Creates a new TexturedPanel that tiles the provided image.
   */
  public TexturedPanel(Image texture) {
    super();
    ourDefaultForeground = Color.white;
    ourDefaultBackground = getBackground();
    if (texture != null)
      setupImagePainter(texture);
    else
      setupDefaultPainter(ourDefaultForeground, ourDefaultBackground);
  }
  /**
   * Creates a new TexturedPanel that tiles the provided icon.
   */
  public TexturedPanel(Icon textureIcon) {
    super();
    ourDefaultForeground = Color.white;
    ourDefaultBackground = getBackground();
    if (textureIcon != null) {
      setupIconPainter(textureIcon);
    }
    else
      setupDefaultPainter(ourDefaultForeground, ourDefaultBackground);
  }
  /**
   * Sets up this TexturedPanel to paint a simple background based on the
   * provided texture and consisting of the provided colors.
   */
  public void setTexture(Color foreground, Color background, boolean[][] texture) {
    if (foreground != null && background != null && texture != null && texture.length > 0
        && texture[0].length > 0) {
      setupTexturePainter(foreground, background, texture, 1);
    }
  }
  /**
   * 
   */
  public void setTexture(Color foreground, Color background, boolean[][] texture, int scale) {
    setupTexturePainter(foreground, background, texture, scale);
  }
  /**
   * Sets up this TexturedPanel to paint a striped background consisting of the
   * provided colors.
   */
  public void setTextureColors(Color foreground, Color background) {
    if (foreground != null && background != null) {
      ourDefaultForeground = foreground;
      ourDefaultBackground = background;
      setupDefaultPainter(foreground, background);
    }
  }
  /**
   * Sets up this TexturedPanel to paint a tiled background consisting of the
   * provided image. If the image is null, the background will revert to a
   * striped texture consisting of the last known colors.
   */
  public void setTextureImage(Image texture) {
    if (texture != null)
      setupImagePainter(texture);
    else
      setupDefaultPainter(ourDefaultForeground, ourDefaultBackground);
  }
  /**
   * Sets up this TexturedPanel to paint a tiled background consisting of the
   * provided icon. If the icon is null, the background will revert to a striped
   * texture consisting of the last known colors.
   */
  public void setTextureIcon(Icon textureIcon) {
    if (textureIcon != null) {
      setupIconPainter(textureIcon);
    }
    else
      setupDefaultPainter(ourDefaultForeground, ourDefaultBackground);
  }
  /**
   * Returns the image buffer used by this TexturedPanel"s painter.
   */
  public Image getTexture() {
    if (ourPainter == null)
      return null;
    else
      return ourPainter.getImage();
  }
  /**
   * Creates a new TexturePaint using the provided colors.
   */
  private void setupDefaultPainter(Color foreground, Color background) {
    if (foreground == null || background == null) {
      ourPainter = null;
      return;
    }
    BufferedImage buff = new BufferedImage(6, 6, BufferedImage.TYPE_INT_ARGB_PRE);
    Graphics2D g2 = buff.createGraphics();
    g2.setColor(background);
    g2.fillRect(0, 0, 6, 6);
    g2.setColor(foreground);
    g2.drawLine(0, 2, 6, 2);
    g2.drawLine(0, 5, 6, 5);
    ourPainter = new TexturePaint(buff, new Rectangle(0, 0, 6, 6));
    g2.dispose();
  }
  /**
   * Creates a new TexturePaint using the provided colors and texture map.
   */
  private void setupTexturePainter(Color foreground, Color background, boolean[][] texture,
      int scale) {
    if (texture == null || texture.length < 1 || texture[0].length < 1) {
      setupDefaultPainter(foreground, background);
      return;
    }
    else if (foreground == null || background == null) {
      ourPainter = null;
      return;
    }
    scale = Math.max(1, scale);
    int w = texture[0].length;
    int h = texture.length;
    BufferedImage buff = new BufferedImage(w * scale, h * scale, BufferedImage.TYPE_INT_ARGB_PRE);
    Graphics2D g2 = buff.createGraphics();
    g2.setColor(background);
    g2.fillRect(0, 0, w * scale, h * scale);
    g2.setColor(foreground);
    for (int i = 0; i < h; i++) {
      for (int j = 0; j < w; j++) {
        try {
          if (texture[i][j])
            g2.fillRect(j * scale, i * scale, scale, scale);
        }
        // g2.drawLine(j, i, j, i); }
        catch (ArrayIndexOutOfBoundsException aob) {
        }
      }
    }
    ourPainter = new TexturePaint(buff, new Rectangle(0, 0, w * scale, h * scale));
    g2.dispose();
  }
  /**
   * Creates a new TexturePaint using the provided image.
   */
  private void setupImagePainter(Image texture) {
    if (texture == null) {
      ourPainter = null;
      return;
    }
    int w = texture.getWidth(this);
    int h = texture.getHeight(this);
    if (w <= 0 || h <= 0) {
      ourPainter = null;
      return;
    }
    BufferedImage buff = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);
    Graphics2D g2 = buff.createGraphics();
    g2.drawImage(texture, 0, 0, this);
    ourPainter = new TexturePaint(buff, new Rectangle(0, 0, w, h));
    g2.dispose();
  }
  /**
   * Creates a new TexturePaint using the provided icon.
   */
  private void setupIconPainter(Icon texture) {
    if (texture == null) {
      ourPainter = null;
      return;
    }
    int w = texture.getIconWidth();
    int h = texture.getIconHeight();
    if (w <= 0 || h <= 0) {
      ourPainter = null;
      return;
    }
    BufferedImage buff = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);
    Graphics2D g2 = buff.createGraphics();
    texture.paintIcon(this, g2, 0, 0);
    ourPainter = new TexturePaint(buff, new Rectangle(0, 0, w, h));
    g2.dispose();
  }
  /**
   * Paints this component with its textured background.
   */
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (ourPainter != null) {
      int w = getWidth();
      int h = getHeight();
      Insets in = getInsets();
      int x = in.left;
      int y = in.top;
      w = w - in.left - in.right;
      h = h - in.top - in.bottom;
      if (w >= 0 && h >= 0) {
        Graphics2D g2 = (Graphics2D) g;
        Paint pt = g2.getPaint();
        g2.setPaint(ourPainter);
        g2.fillRect(x, y, w, h);
        g2.setPaint(pt);
      }
    }
  }
}





Gradient Panel

  
/*
 *  soapUI, copyright (C) 2004-2009 eviware.ru 
 *
 *  soapUI is free software; you can redistribute it and/or modify it under the 
 *  terms of version 2.1 of the GNU Lesser General Public License as published by 
 *  the Free Software Foundation.
 *
 *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *  See the GNU Lesser General Public License for more details at gnu.org.
 */

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager;
import java.awt.Paint;
import javax.swing.JPanel;
/**
 * Created by IntelliJ IDEA.
 */
public class GradientPanel extends JPanel
{
  // ------------------------------ FIELDS ------------------------------
  public final static int HORIZONTAL = 0;
  public final static int VERTICAL = 1;
  public final static int DIAGONAL_LEFT = 2;
  public final static int DIAGONAL_RIGHT = 3;
  private int direction = HORIZONTAL;
  private boolean cyclic;
  private int maxLength;
  // --------------------------- CONSTRUCTORS ---------------------------
  public GradientPanel()
  {
    this( HORIZONTAL );
  }
  public GradientPanel( int direction )
  {
    super( new BorderLayout() );
    setOpaque( false );
    this.direction = direction;
  }
  public GradientPanel( LayoutManager layoutManager )
  {
    super( layoutManager );
    setOpaque( false );
    this.direction = HORIZONTAL;
  }
  // --------------------- GETTER / SETTER METHODS ---------------------
  public int getDirection()
  {
    return direction;
  }
  public void setDirection( int direction )
  {
    this.direction = direction;
  }
  public boolean isCyclic()
  {
    return cyclic;
  }
  public void setCyclic( boolean cyclic )
  {
    this.cyclic = cyclic;
  }
  public void setMaxLength( int maxLength )
  {
    this.maxLength = maxLength;
  }
  // -------------------------- OTHER METHODS --------------------------
  public void paintComponent( Graphics g )
  {
    if( isOpaque() )
    {
      super.paintComponent( g );
      return;
    }
    int width = getWidth();
    int height = getHeight();
    // Create the gradient paint
    GradientPaint paint = null;
    Color sc = getForeground();
    Color ec = getBackground();
    switch( direction )
    {
    case HORIZONTAL :
    {
      paint = new GradientPaint( 0, height / 2, sc, width, height / 2, ec, cyclic );
      break;
    }
    case VERTICAL :
    {
      paint = new GradientPaint( width / 2, 0, sc, width / 2, maxLength > 0 ? maxLength : height, ec, cyclic );
      break;
    }
    case DIAGONAL_LEFT :
    {
      paint = new GradientPaint( 0, 0, sc, width, height, ec, cyclic );
      break;
    }
    case DIAGONAL_RIGHT :
    {
      paint = new GradientPaint( width, 0, sc, 0, height, ec, cyclic );
      break;
    }
    }
    if( paint == null )
    {
      throw new RuntimeException( "Invalid direction specified in GradientPanel" );
    }
    // we need to cast to Graphics2D for this operation
    Graphics2D g2d = ( Graphics2D )g;
    // save the old paint
    Paint oldPaint = g2d.getPaint();
    // set the paint to use for this operation
    g2d.setPaint( paint );
    // fill the background using the paint
    g2d.fillRect( 0, 0, width, height );
    // restore the original paint
    g2d.setPaint( oldPaint );
    super.paintComponent( g );
  }
}





Graph Canvas

    
/*
 * The contents of this file are subject to the Sapient Public License
 * Version 1.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * http://carbon.sf.net/License.html.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is The Carbon Component Framework.
 *
 * The Initial Developer of the Original Code is Sapient Corporation
 *
 * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
 */

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** <p>This class provides a consistent space within to graph real
 * numbers. It provides features such as auto-centering and
 * real-time scaling. A user of this graph provides data by creating
 * one or more tracks and then adding real points to those. Calling
 * translate periodically allows you to create a scrolling graph as
 * well.</p>
 *
 * <p>This graph will also maintain tick marks that resize and
 * can be stuck to the sides of the screen so they are always
 * visible even if the origin is off-screen.</p>
 *
 * Copyright 2001 Sapient
 * @author Greg Hinkle
 * @version $Revision: 1.4 $ ($Author: dvoet $ / $Date: 2003/05/05 21:21:26 $)
 */
public class GraphCanvas extends JPanel {
    /** A list of  Track"s that are a part of this graph */
    private Map tracks = new HashMap(11);
    /** The current graph bounds that are visible */
    protected Rectangle2D graphBounds;
    /** The portion of the entire height that should be researved as
     * a border, above and below the highest and lowest track points */
    private static final double BORDER_PERCENT = 0.1d;
    /** The background color for this graph */
    protected Color backgroundColor = new Color(204,204,204);
    protected static NumberFormat labelFormat = null;
    protected static NumberFormat bigNumberLabelFormat = null;
    /**
     * Instantiates a graph canvas
     */
    public GraphCanvas() {
        super();
        setBackground(Color.blue);
        this.graphBounds = new Rectangle2D.Double(-5,0,150,2);

        this.labelFormat = NumberFormat.getNumberInstance();
        this.labelFormat.setMaximumFractionDigits(2);
        this.bigNumberLabelFormat = NumberFormat.getNumberInstance();
        this.bigNumberLabelFormat.setMaximumFractionDigits(0);

        System.out.println("GraphCanvas::<init> - New GraphCanvas created.");
    }
    /**
     * <p>Sets the background color of this graph
     *
     * @param color the Color to set the background to
     */
    public void setBackgroundColor(Color color) {
        this.backgroundColor = color;
    }
    /** Gets the bounds of the graphing space that are currently showing
     * on the screen.
     * @return Rectangle2D The bounds of the currently visible graph
     */
    public Rectangle2D getGraphBounds() {
        return this.graphBounds;
    }
    /**
     * Sets the bounds that this graph is displaying
     *
     * @param rect the Rectangle2D of the desired graph points
     */
    public void setGraphBounds(Rectangle2D rect) {
        this.graphBounds = rect;
    }

    public AffineTransform getTransform() {
        AffineTransform affineT =
        new AffineTransform(1d,0d,0d,-1d,0d,super.getParent().getHeight());

        // scale to current scale
        affineT.concatenate(
        AffineTransform.getScaleInstance(
        this.getBounds().getWidth() / this.graphBounds.getWidth(),
        this.getBounds().getHeight() / this.graphBounds.getHeight()));
        // translate to the current origin
        affineT.concatenate(
        AffineTransform.getTranslateInstance(
        -this.graphBounds.getX(),
        -this.graphBounds.getY()));
        return affineT;
    }

    // CLEAR ALL CURVES FROM PLOT
    public void clear() {
    }
    public void addTrack(String trackName) {
        this.tracks.put(trackName, new Track(trackName));
    }
    public void addTrack(String trackName,Color color) {
        this.tracks.put(trackName, new Track(trackName,color));
    }

    // ADD CURVE TO STORAGE (DOESN"T GRAPH UNTIL REPAINT()).
    public void addPoint(String track, Point2D point) {
        ((Track)this.tracks.get(track)).addPoint(point);
    }
    public Track getTrack(String trackName) {
        return (Track) this.tracks.get(trackName);
    }


    public void clearAll() {
        this.getGraphics().clearRect(
        (int)getBounds().getX(),
        (int)getBounds().getY(),
        (int)getBounds().getWidth(),
        (int)getBounds().getHeight());
    }
    public void paint(Graphics gg) {
        Graphics2D g = (Graphics2D) gg;
        g.setBackground(this.backgroundColor);
        // What is the current graph to panel transform
        AffineTransform newTrans = getTransform();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);

        // Erase this entire graph so that we can redraw it
        g.clearRect(
            (int)getBounds().getX(),
            (int)getBounds().getY(),
            (int)getBounds().getWidth(),
            (int)getBounds().getHeight());

        // This draws the tick marks and the tick values
        drawLines(g,newTrans);
        // This drawes the axeses
        drawAxes(g,newTrans);
        // This draws each of tracks in this graph
        drawTracks(g,newTrans);
        // This draws the keys for each graph
        drawKey(g,newTrans);
    }
    /**
     * <p>Draw the key to the tracks by calling thier toString</p>
     *
     * @param graphics2D the Graphics2D to draw to
     * @param transform the Affine Transform to use to determine how to draw
     */
    protected void drawKey(Graphics2D g, AffineTransform transform) {
        int start = 20;
        Iterator trackIterator = this.tracks.values().iterator();
        while(trackIterator.hasNext()) {
            Track track = (Track) trackIterator.next();
            String info = track.toString();
            // Will draw the key in the same color as it"s line
            g.setColor(track.getColor());
            g.drawString(info,50, start+=25);
        }
    }
    protected void drawTracks(Graphics2D g, AffineTransform transform) {
        // Store original transform to restore it later
        // until I figure out how to track differences only
        AffineTransform origTrans = g.getTransform();

        // Transform for local drawing
        g.transform(transform);
        g.setColor(Color.orange);
        // Using a small stroke will minimize the width to a single output
        // level pixel up to a reasonable scaling size
        g.setStroke(new BasicStroke(0.001f));
        // Draw the tracks
        Iterator trackIterator = this.tracks.values().iterator();
        while (trackIterator.hasNext()) {
            Track track = (Track) trackIterator.next();
            g.setColor(track.getColor());
            GeneralPath path = track.getPath();
            g.draw(path);
        }
        // Reset transformation
        g.setTransform(origTrans);
    }
    /**
     * This draws the axes
     */
    protected void drawAxes(Graphics2D g,AffineTransform transform) {
        g.setColor(Color.white);
        Point2D origin = transform.transform(new Point2D.Double(0,0),null);
        // If you want to have rubber banding axes (always visible)
        Rectangle2D axesRect = new Rectangle2D.Double(5,5,this.bounds().getWidth()-10,this.bounds().getHeight());
        origin = floorPoint(origin,axesRect);
        Line2D x = new Line2D.Double(
        getBounds().getMinX(), origin.getY(),
        getBounds().getMaxX(), origin.getY());
        Line2D y = new Line2D.Double(
        origin.getX(), getBounds().getMinY(),
        origin.getX(), getBounds().getMaxY());
        g.draw(x);
        g.draw(y);
    }

    /**
     * <p>This finds the closest point on a rectangle"s edge to a point outside
     * the rectangle or if that point is within the rectangle it is returned.
     * </p>
     *
     * @param point The point to rectangularly floor
     * @param rect The rectangle to floor within
     */
    public static Point2D floorPoint(Point2D point, Rectangle2D rect) {
        double x = point.getX();
        double y = point.getY();
        if (x < rect.getMinX())
            x = rect.getMinX();
        if (x > rect.getMaxX())
            x = rect.getMaxX();
        if (y < rect.getMinY())
            y = rect.getMinY();
        if (y > rect.getMaxY())
            y = rect.getMaxY();
        return new Point2D.Double(x,y);
    }

    /**
     * <p>This draws the tick marks in the graph
     *
     */
    protected void drawLines(Graphics2D g, AffineTransform transform) {
        g.setColor(Color.white);
        int REAL_TICK_SPACE = 40;
        int REAL_TICK_HEIGHT = 10;
        double graphTickSpaceX = (REAL_TICK_SPACE / transform.getScaleX());
        double graphTickSpaceY = (REAL_TICK_SPACE / Math.abs(transform.getScaleY()));

        Point2D origin = transform.transform(new Point2D.Float(0,0),null);
        // If you want to have rubber banding axes (always visible)
        Rectangle2D axesRect = new Rectangle2D.Double(5,5,this.bounds().getWidth()-10,this.bounds().getHeight());
        Point2D falseOrigin = floorPoint(origin,axesRect);
        double firstX = this.graphBounds.getMinX();
        Point2D pt = new Point2D.Float();
        for (double x = firstX; x <= (this.graphBounds.getMaxX()+graphTickSpaceX); x += graphTickSpaceX) {
            double tx = (Math.floor(x/graphTickSpaceX)) * graphTickSpaceX;
            pt.setLocation(tx,0);
            transform.transform(pt,pt);
            g.drawLine((int)pt.getX(),(int)falseOrigin.getY() - 5 ,(int)pt.getX(),(int)falseOrigin.getY() + 5);
            String label;
            if (tx > 10)
                label = this.bigNumberLabelFormat.format(tx);
            else
                label = this.labelFormat.format(tx);
            g.drawString(label,
                (float)pt.getX(),(float)falseOrigin.getY()-9);
        }

        double firstY = this.graphBounds.getMinY();
        for (double y = firstY; y <= (this.graphBounds.getMaxY()+graphTickSpaceY); y += graphTickSpaceY) {
            double ty = (Math.floor(y/graphTickSpaceY)) * graphTickSpaceY;
            pt.setLocation(0,ty);
            transform.transform(pt,pt);
            g.drawLine((int)falseOrigin.getX() - 5,(int)pt.getY() ,(int)falseOrigin.getX() + 5,(int)pt.getY());
            String label;
            if (ty > 10)
                label = this.bigNumberLabelFormat.format(ty);
            else
                label = this.labelFormat.format(ty);
            g.drawString(label,
                (float)falseOrigin.getX()+7,(float)pt.getY());
        }
    }
    public static class Track {
        protected String name;
        protected Color color = Color.black;  //Default to black
        protected GeneralPath path = new GeneralPath();
        protected boolean started = false;
        protected NumberFormat keyFormat;
        public Track(String name) {
            super();
            this.name = name;
            this.keyFormat = NumberFormat.getNumberInstance();
            this.keyFormat.setMaximumFractionDigits(2);
        }
        public Track(String name, Color color) {
            this(name);
            this.color = color;
        }
        public void setPath(GeneralPath path) {
            this.path = path;
        }
        public GeneralPath getPath() {
            return this.path;
        }
        public void addPoint(Point2D point) {
            if (path.getCurrentPoint() == null) {
                this.path.moveTo((float)point.getX(),(float)point.getY());
                this.started = true;
            } else {
                this.path.lineTo((float)point.getX(),(float)point.getY());
            }
        }
        public Color getColor() {
            return this.color;
        }
        public void setColor(Color color) {
            this.color = color;
        }
        public String toString() {
            String value = null;
            if (this.path.getCurrentPoint() != null) {
                double val = this.path.getCurrentPoint().getY();
                //NumberFormat nf = NumberFormat.getNumberInstance();
                value = this.keyFormat.format(val);
            }
            return this.name + ": " + value;
        }
    }

    /**
     * <p>Bounds the graph to the limits of the tracks verticaly providing a
     * useful scaling. A more intelligent implementation could have minimum
     * bounds to limit the bouncyness to startup.</p>
     */
    public void verticalBound() {
        Rectangle2D rect = null;
        Rectangle2D orig = getGraphBounds();
        Iterator trackIterator = this.tracks.values().iterator();
        while(trackIterator.hasNext()) {
            Track track = (Track) trackIterator.next();
            GeneralPath path = track.getPath();
            if (rect == null)
                rect = path.getBounds2D();
            else
                Rectangle.union(rect,path.getBounds2D(),rect);
        }
        Rectangle.union(rect,new Rectangle2D.Double(orig.getX(),0,1,1),rect);
        double border = rect.getHeight() * BORDER_PERCENT;
        setGraphBounds(new Rectangle2D.Double(
            orig.getMinX(),
            rect.getMinY()-border,
            orig.getWidth(),
            rect.getHeight()+(2d*border)));
    }
    public void clipOld() {
        Rectangle2D rect = getGraphBounds();
        //Rectangle2D orig = AffineTransform.getScaleInstance(1.5,1.5).createTransformedShape(getGraphBounds()).getBounds();
        Iterator trackIterator = this.tracks.values().iterator();
        double[] cs = new double[6];
        while(trackIterator.hasNext()) {
            Track track = (Track) trackIterator.next();
            GeneralPath path = track.getPath();
            GeneralPath newPath = new GeneralPath();
            PathIterator pIter = path.getPathIterator(new AffineTransform());
            while (!pIter.isDone()) {
                pIter.currentSegment(cs);
                //Point2D pt = new Point2D.Double(cs[0],cs[1]);
                if (cs[0] > rect.getMinX()) {
                    if (newPath.getCurrentPoint() == null)
                        newPath.moveTo((float)cs[0],(float)cs[1]);
                    else
                        newPath.lineTo((float)cs[0],(float)cs[1]);
                }
                /*
                System.out.println("Current Segment: " +
                cs[0] + ", " +
                cs[1] + ", " +
                cs[2] + ", " +
                cs[3] + ", " +
                cs[4] + ", " +
                cs[5]);
                 **/
                pIter.next();
            }
            track.setPath(newPath);
        }
    }
    /**
     * <p>Translates the main graph rect by x and y, horizontally and vertically
     * respectively.</p>
     */
    public void translate(double x, double y) {

        Rectangle2D rect = getGraphBounds();
        setGraphBounds(
        new Rectangle2D.Double(rect.getMinX()+x,
        rect.getMinY()+y,rect.getWidth(),rect.getHeight()));
    }
    public static void main(String[] args) throws Exception {
        GraphCanvas gc = new GraphCanvas();
        gc.show();
        JFrame frame = new JFrame("Memory Graph");
        frame.getContentPane().add(gc);
        frame.setSize(600,200);
        // TODO: Add window exit listener
        frame.show();
        gc.repaint();
        gc.paint((Graphics2D)gc.getGraphics());

        long start = System.currentTimeMillis();
        gc.addTrack("test", Color.cyan);
        gc.addTrack("test2", Color.blue);
        gc.addTrack("test3", Color.red);
        gc.addTrack("test4", Color.yellow);
        gc.addTrack("test5", Color.green);
        gc.addTrack("test6", Color.orange);
        gc.addTrack("test7", Color.pink);

        int i=0;
        while (true) {
            i++;
            Point2D pt = new Point2D.Float(i,((float)Math.cos(i/20f) + (float)Math.sin(i/40f)) * 3f);
            gc.addPoint("test",pt);
            Point2D pt2 = new Point2D.Float(i,(float)Math.cos(i/25.0f)*10f);
            gc.addPoint("test2",pt2);
            Point2D pt3 = new Point2D.Float(i,Math.min((float)Math.cos(Math.sin(i/4f))*13f - (float)Math.cos(i/80f)*20f,400f));
            gc.addPoint("test3",pt3);
            Point2D pt4 = new Point2D.Float(i,
                (float) Math.sin(.31*i)*2f +
                ((float)2f*(float)Math.cos(.07f*i))*8f);
            gc.addPoint("test4",pt4);
            Point2D pt5 = new Point2D.Float(i,
                (float) Math.cos(.66*i)*1f +
                ((float)2f*(float)Math.cos(.07f*i))*3f);
            gc.addPoint("test5",pt5);
            Point2D pt6 = new Point2D.Float(i,
                (float) Math.sin(.31*i)*2f +
                ((float)2f*(float)Math.cos(.07f*Math.tan(i)))*5f);
            gc.addPoint("test6",pt6);
            Point2D pt7 = new Point2D.Float(i,
                (float) Math.sin(i)*2f +
                ((float)2f*(float)Math.sin(.25f*i))*0.5f);
            gc.addPoint("test7",pt7);

            if (i > 150)
                gc.translate(1,0);
            gc.verticalBound();
            //if(i%100 == 0) {
                gc.clipOld();
            //}
            gc.repaint();
            Thread.sleep(10);
            if (i % 100 == 0) {
                System.out.println("Framewrate: " +
                    (100d / ((System.currentTimeMillis()-start)/1000d)));
                start = System.currentTimeMillis();
            }
        }
    }
}





Swing Panel Group

  
(From http://swinglabs.org/downloads.jsp)





Swing Panel Group 2

  
(From http://swinglabs.org/downloads.jsp)





Time panel shows the current time.

    
/*
 * Copyright (C) 2002-2003 Colin Bell
 * colbell@users.sourceforge.net
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.util.Calendar;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.border.Border;
/**
 * Time panel. This will show the current time.
 * A timer to update the time is started when the component
 * is added to its parent and stopped when removed from its parent.
 *
 * @author 
 */
public class TimePanel extends JLabel implements ActionListener
{
  /** Timer that updates time. */
  private Timer _timer;
  /** Used to format the displayed date. */
  private DateFormat _fmt = DateFormat.getTimeInstance(DateFormat.LONG);
  private Dimension _prefSize;
  private Calendar _calendar = Calendar.getInstance();
  /**
   * Default ctor.
   */
  public TimePanel()
  {
    super("", JLabel.CENTER);
  }
  /**
   * Add component to its parent. Start the timer for auto-update.
   */
  public void addNotify()
  {
    super.addNotify();
    _timer = new Timer(1000, this);
    _timer.start();
  }
  /**
   * Remove component from its parent. Stop the timer.
   */
  public void removeNotify()
  {
    super.removeNotify();
    if (_timer != null)
    {
      _timer.stop();
      _timer = null;
    }
  }
  /**
   * Update component with the current time.
   *
   * @param evt   The current event.
   */
  public void actionPerformed(ActionEvent evt)
  {
    _calendar.setTimeInMillis(System.currentTimeMillis());
    setText(_fmt.format(_calendar.getTime()));
  }
  /**
   * Return the preferred size of this component.
   *
   * @return  the preferred size of this component.
   */
  public Dimension getPreferredSize()
  {
    if(null == _prefSize)
    {
      // This was originaly done every time.
      // and the count of instantiated objects was amazing
      _prefSize = new Dimension();
      _prefSize.height = 20;
      FontMetrics fm = getFontMetrics(getFont());
      Calendar cal = Calendar.getInstance();
      cal.set(Calendar.HOUR_OF_DAY, 23);
      cal.set(Calendar.MINUTE, 59);
      cal.set(Calendar.SECOND, 59);
      _prefSize.width = fm.stringWidth(_fmt.format(cal.getTime()));
      Border border = getBorder();
      if (border != null)
      {
        Insets ins = border.getBorderInsets(this);
        if (ins != null)
        {
          _prefSize.width += (ins.left + ins.right);
        }
      }
      Insets ins = getInsets();
      if (ins != null)
      {
        _prefSize.width += (ins.left + ins.right) + 20;
      }
    }
    return _prefSize;
  }
}





Transfer focus from button to button with help of arrows keys.

  
/*
 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

import java.awt.BorderLayout;
import java.awt.ruponent;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.DefaultButtonModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.KeyStroke;
import javax.swing.LayoutFocusTraversalPolicy;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
/**
 * This is a JPanel subclass which provides a special functionality
 * for its children buttons components.
 * It makes it possible to transfer focus from button to button
 * with help of arrows keys.
 * <p>The following example shows how to enable cyclic focus transfer 
 * <pre>
 * import org.jdesktop.swinghelper.buttonpanel.*; 
 * import javax.swing.*;
 *
 * public class SimpleDemo {
 *     public static void main(String[] args) throws Exception {
 *         SwingUtilities.invokeLater(new Runnable() {
 *             public void run() {
 *                 final JFrame frame = new JFrame();
 *                 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 *       
 *                 JXButtonPanel panel = new JXButtonPanel();
 *                 panel.setCyclic(true);
 *       
 *                 panel.add(new JButton("One"));
 *                 panel.add(new JButton("Two"));
 *                 panel.add(new JButton("Three"));
 *       
 *                 frame.add(panel);
 *                 frame.setSize(200, 200);
 *                 frame.setLocationRelativeTo(null);
 *                 frame.setVisible(true);
 *             }
 *         });
 *     }
 * }
 * </pre> 
 *  
 * If your buttons inside JXButtonPanel are added to one ButtonGroup
 * arrow keys will transfer selection between them as well as they do it for focus<p>
 * Note: you can control this behaviour with setGroupSelectionFollowFocus(boolean) 
 * <pre>
 * import org.jdesktop.swinghelper.buttonpanel.*;
 * import javax.swing.*;
 *
 * public class RadioButtonDemo {
 *     public static void main(String[] args) throws Exception {
 *         SwingUtilities.invokeLater(new Runnable() {
 *             public void run() {
 *                 final JFrame frame = new JFrame();
 *                 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 * 
 *                 JXButtonPanel panel = new JXButtonPanel();
 *                 ButtonGroup group = new ButtonGroup();
 * 
 *                 JRadioButton rb1 = new JRadioButton("One");
 *                 panel.add(rb1);
 *                 group.add(rb1);
 *                 JRadioButton rb2 = new JRadioButton("Two");
 *                 panel.add(rb2);
 *                 group.add(rb2);
 *                 JRadioButton rb3 = new JRadioButton("Three");
 *                 panel.add(rb3);
 *                 group.add(rb3);
 * 
 *                 rb1.setSelected(true);
 *                 frame.add(panel);
 * 
 *                 frame.setSize(200, 200);
 *                 frame.setLocationRelativeTo(null);
 *                 frame.setVisible(true);
 *             }
 *         });
 *     }
 * }
 * </pre> 
 * 
 * @author Alexander Potochkin
 * 
 * https://swinghelper.dev.java.net/
 * http://weblogs.java.net/blog/alexfromsun/ 
 */
public class JXButtonPanel extends JPanel {
    private boolean isCyclic;
    private boolean isGroupSelectionFollowFocus;
    /**
     * {@inheritDoc}
     */
    public JXButtonPanel() {
        super();
        init();
    }
    /**
     * {@inheritDoc}
     */
    public JXButtonPanel(LayoutManager layout) {
        super(layout);
        init();
    }
    /**
     * {@inheritDoc}    
     */
    public JXButtonPanel(boolean isDoubleBuffered) {
        super(isDoubleBuffered);
        init();
    }
    /**
     * {@inheritDoc}
     */
    public JXButtonPanel(LayoutManager layout, boolean isDoubleBuffered) {
        super(layout, isDoubleBuffered);
        init();
    }
    private void init() {
        setFocusTraversalPolicyProvider(true);
        setFocusTraversalPolicy(new JXButtonPanelFocusTraversalPolicy());
        ActionListener actionHandler = new ActionHandler();
        registerKeyboardAction(actionHandler, ActionHandler.FORWARD,
                KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
                JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        registerKeyboardAction(actionHandler, ActionHandler.FORWARD,
                KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
                JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        registerKeyboardAction(actionHandler, ActionHandler.BACKWARD,
                KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
                JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        registerKeyboardAction(actionHandler, ActionHandler.BACKWARD,
                KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
                JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        setGroupSelectionFollowFocus(true);
    }
    /**
     * Returns whether arrow keys should support
     * cyclic focus traversal ordering for for this JXButtonPanel.   
     */
    public boolean isCyclic() {
        return isCyclic;
    }
    /**
     * Sets whether arrow keys should support
     * cyclic focus traversal ordering for this JXButtonPanel.
     */
    public void setCyclic(boolean isCyclic) {
        this.isCyclic = isCyclic;
    }
    /**
     * Returns whether arrow keys should transfer button"s 
     * selection as well as focus for this JXButtonPanel.<p>
     * 
     * Note: this property affects buttons which are added to a ButtonGroup 
     */
    public boolean isGroupSelectionFollowFocus() {
        return isGroupSelectionFollowFocus;
    }
    /**
     * Sets whether arrow keys should transfer button"s
     * selection as well as focus for this JXButtonPanel.<p>
     * 
     * Note: this property affects buttons which are added to a ButtonGroup 
     */
    public void setGroupSelectionFollowFocus(boolean groupSelectionFollowFocus) {
        isGroupSelectionFollowFocus = groupSelectionFollowFocus;
    }
    private static ButtonGroup getButtonGroup(AbstractButton button) {
        ButtonModel model = button.getModel();
        if (model instanceof DefaultButtonModel) {
            return ((DefaultButtonModel) model).getGroup();
        }
        return null;
    }
    private class ActionHandler implements ActionListener {
        private static final String FORWARD = "moveSelectionForward";
        private static final String BACKWARD = "moveSelectionBackward";
        public void actionPerformed(ActionEvent e) {
            FocusTraversalPolicy ftp = JXButtonPanel.this.getFocusTraversalPolicy();
            if (ftp instanceof JXButtonPanelFocusTraversalPolicy) {
                JXButtonPanelFocusTraversalPolicy xftp =
                        (JXButtonPanelFocusTraversalPolicy) ftp;
                String actionCommand = e.getActionCommand();
                Component fo =
                        KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
                Component next;
                xftp.setAlternativeFocusMode(true);
                if (FORWARD.equals(actionCommand)) {
                    next = xftp.getComponentAfter(JXButtonPanel.this, fo);
                } else if (BACKWARD.equals(actionCommand)) {
                    next = xftp.getComponentBefore(JXButtonPanel.this, fo);
                } else {
                    throw new AssertionError("Unexpected action command: " + actionCommand);
                }
                xftp.setAlternativeFocusMode(false);
                if (fo instanceof AbstractButton) {
                    AbstractButton b = (AbstractButton) fo;
                    b.getModel().setPressed(false);
                }
                if (next != null) {
                    if (fo instanceof AbstractButton && next instanceof AbstractButton) {
                        ButtonGroup group = getButtonGroup((AbstractButton) fo);
                        AbstractButton nextButton = (AbstractButton) next;
                        if (group != getButtonGroup(nextButton)) {
                            return;
                        }
                        if (isGroupSelectionFollowFocus() && group != null && 
                                group.getSelection() != null && !nextButton.isSelected()) {
                            nextButton.setSelected(true);
                        }
                        next.requestFocusInWindow();
                    }
                }
            }
        }
    }
    private class JXButtonPanelFocusTraversalPolicy extends LayoutFocusTraversalPolicy {
        private boolean isAlternativeFocusMode;
        public boolean isAlternativeFocusMode() {
            return isAlternativeFocusMode;
        }
        public void setAlternativeFocusMode(boolean alternativeFocusMode) {
            isAlternativeFocusMode = alternativeFocusMode;
        }
        protected boolean accept(Component c) {
            if (!isAlternativeFocusMode() && c instanceof AbstractButton) {
                AbstractButton button = (AbstractButton) c;
                ButtonGroup group = JXButtonPanel.getButtonGroup(button);
                if (group != null && group.getSelection() != null
                        && !button.isSelected()) {
                    return false;
                }
            }
            return super.accept(c);
        }
        public Component getComponentAfter(Container aContainer, Component aComponent) {
            Component componentAfter = super.getComponentAfter(aContainer, aComponent);
            if (!isAlternativeFocusMode()) {
                return componentAfter;
            }
            if (JXButtonPanel.this.isCyclic()) {
                return componentAfter == null ?
                        getFirstComponent(aContainer) : componentAfter;
            }
            if (aComponent == getLastComponent(aContainer)) {
                return aComponent;
            }
            return componentAfter;
        }
        public Component getComponentBefore(Container aContainer, Component aComponent) {
            Component componentBefore = super.getComponentBefore(aContainer, aComponent);
            if (!isAlternativeFocusMode()) {
                return componentBefore;
            }
            if (JXButtonPanel.this.isCyclic()) {
                return componentBefore == null ?
                        getLastComponent(aContainer) : componentBefore;
            }
            if (aComponent == getFirstComponent(aContainer)) {
                return aComponent;
            }
            return componentBefore;
        }
    }
}


/**
 * @author Alexander Potochkin
 * 
 * https://swinghelper.dev.java.net/
 * http://weblogs.java.net/blog/alexfromsun/ 
 */
class JXButtonPanelDemo extends JFrame {
    private ButtonGroup radioGroup = new ButtonGroup();
    public JXButtonPanelDemo() {
        super("JXButtonPanel demo");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        JPanel topPanel = new JPanel(new GridLayout(1, 0));
        
        final JXButtonPanel radioGroupPanel = createRadioJXButtonPanel();
        topPanel.add(radioGroupPanel);
        
        final JXButtonPanel checkBoxPanel = createCheckBoxJXButtonPanel();
        topPanel.add(checkBoxPanel);
        add(topPanel);
        add(createButtonJXButtonPanel(), BorderLayout.SOUTH);
        pack();
        JMenuBar bar = new JMenuBar();
        JMenu menu = new JMenu("Options");
        JMenuItem item = new JMenuItem("Unselect radioButtons");
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.ALT_MASK));
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                // hack for 1.5 
                // in 1.6 ButtonGroup.clearSelection added
                JRadioButton b = new JRadioButton();
                radioGroup.add(b);
                b.setSelected(true);
                radioGroup.remove(b);
            }
        });
        menu.add(item);
        bar.add(menu);
        setJMenuBar(bar);
        setSize(300, 300);
        setLocationRelativeTo(null);
    }
    private JXButtonPanel createRadioJXButtonPanel() {
        JXButtonPanel panel = new JXButtonPanel();
        panel.setLayout(new GridLayout(0, 1));
        JRadioButton one = new JRadioButton("One");
        panel.add(one);
        radioGroup.add(one);
        JRadioButton two = new JRadioButton("Two");
        panel.add(two);
        radioGroup.add(two);
        JRadioButton three = new JRadioButton("Three");
        panel.add(three);
        radioGroup.add(three);
        JRadioButton four = new JRadioButton("Four");
        panel.add(four);
        radioGroup.add(four);
        one.setSelected(true);
        panel.setBorder(BorderFactory.createTitledBorder("JXButtonPanel"));
        return panel;
    }
    private JXButtonPanel createCheckBoxJXButtonPanel() {
        JXButtonPanel panel = new JXButtonPanel();
        panel.setLayout(new GridLayout(0, 1));
        JCheckBox one = new JCheckBox("One");
        panel.add(one);
        JCheckBox two = new JCheckBox("Two");
        panel.add(two);
        JCheckBox three = new JCheckBox("Three");
        panel.add(three);
        JCheckBox four = new JCheckBox("Four");
        panel.add(four);
        panel.setBorder(BorderFactory.createTitledBorder("JXButtonPanel"));
        return panel;
    }
    private JPanel createButtonJXButtonPanel() {
        JPanel ret = new JPanel(new BorderLayout());
        JLabel label = new JLabel("Does JXButtonPanel support arrow keys ?");
        label.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
        JPanel temp = new JPanel();
        temp.add(label);
        ret.add(temp);
        
        JXButtonPanel panel = new JXButtonPanel();
        panel.setCyclic(true);
        panel.add(new JButton("Yes"));
        panel.add(new JButton("Sure"));
        panel.add(new JButton("Absolutely !"));
        panel.setBorder(BorderFactory.createTitledBorder(null, 
                "JXButtonPanel.setCyclic(true)",
                TitledBorder.CENTER, TitledBorder.BOTTOM));
        ret.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
        ret.add(panel, BorderLayout.SOUTH);
        return ret;
    }
    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new JXButtonPanelDemo().setVisible(true);
            }
        });         
    }
}





Transparent Panel

  
(From http://swinglabs.org/downloads.jsp)





Yes / No Panel

  

/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.ru/javaexamples3.
 */
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
class Alignment {
  /** This private constructor prevents anyone from instantiating us */
  private Alignment() {
  };
  // The following three constants are the only instances of this class
  public static final Alignment LEFT = new Alignment();
  public static final Alignment CENTER = new Alignment();
  public static final Alignment RIGHT = new Alignment();
}
/**
 * A custom component that displays multiple lines of text with specified
 * margins and alignment.
 */
class MultiLineLabel extends JComponent {
  // User-specified properties
  protected String label; // The label, not broken into lines
  protected int margin_width; // Left and right margins
  protected int margin_height; // Top and bottom margins
  protected Alignment alignment; // The alignment of the text.
  // Computed state values
  protected int num_lines; // The number of lines
  protected String[] lines; // The label, broken into lines
  protected int[] line_widths; // How wide each line is
  protected int max_width; // The width of the widest line
  protected int line_height; // Total height of the font
  protected int line_ascent; // Font height above baseline
  protected boolean measured = false; // Have the lines been measured?
  // Here are five versions of the constructor.
  public MultiLineLabel(String label, int margin_width, int margin_height, Alignment alignment) {
    this.label = label; // Remember all the properties.
    this.margin_width = margin_width;
    this.margin_height = margin_height;
    this.alignment = alignment;
    newLabel(); // Break the label up into lines.
  }
  public MultiLineLabel(String label, int margin_width, int margin_height) {
    this(label, margin_width, margin_height, Alignment.LEFT);
  }
  public MultiLineLabel(String label, Alignment alignment) {
    this(label, 10, 10, alignment);
  }
  public MultiLineLabel(String label) {
    this(label, 10, 10, Alignment.LEFT);
  }
  public MultiLineLabel() {
    this("");
  }
  // Methods to set and query the various attributes of the component.
  // Note that some query methods are inherited from the superclass.
  public void setLabel(String label) {
    this.label = label;
    newLabel(); // Break the label into lines.
    repaint(); // Request a redraw.
    measured = false; // Note that we need to measure lines.
    invalidate(); // Tell our containers about this
  }
  public void setAlignment(Alignment a) {
    alignment = a;
    repaint();
  }
  public void setMarginWidth(int mw) {
    margin_width = mw;
    repaint();
  }
  public void setMarginHeight(int mh) {
    margin_height = mh;
    repaint();
  }
  // Override this property setter method because we need to remeasure
  public void setFont(Font f) {
    super.setFont(f); // Tell our superclass about the new font.
    repaint(); // Request a redraw.
    measured = false; // Note that we need to remeasure lines.
    invalidate(); // Tell our containers about new size
  }
  // Property getter methods.
  public String getLabel() {
    return label;
  }
  public Alignment getAlignment() {
    return alignment;
  }
  public int getMarginWidth() {
    return margin_width;
  }
  public int getMarginHeight() {
    return margin_height;
  }
  /**
   * This method is called by a layout manager when it wants to know how big
   * we"d like to be.
   */
  public Dimension getPreferredSize() {
    if (!measured)
      measure();
    return new Dimension(max_width + 2 * margin_width, num_lines * line_height + 2 * margin_height);
  }
  /**
   * This method is called when the layout manager wants to know the bare
   * minimum amount of space we need to get by.
   */
  public Dimension getMinimumSize() {
    return getPreferredSize();
  }
  /**
   * This method draws the component. Note that it handles the margins and the
   * alignment, but that it doesn"t have to worry about the color or font--the
   * superclass takes care of setting those in the Graphics object we"re passed.
   */
  public void paintComponent(Graphics g) {
    int x, y;
    Dimension size = this.getSize();
    if (!measured)
      measure();
    y = line_ascent + (size.height - num_lines * line_height) / 2;
    for (int i = 0; i < num_lines; i++, y += line_height) {
      if (alignment == Alignment.LEFT)
        x = margin_width;
      else if (alignment == Alignment.CENTER)
        x = (size.width - line_widths[i]) / 2;
      else
        x = size.width - margin_width - line_widths[i];
      g.drawString(lines[i], x, y);
    }
  }
  /**
   * This internal method breaks a specified label up into an array of lines. It
   * uses the StringTokenizer utility class.
   */
  protected synchronized void newLabel() {
    StringTokenizer t = new StringTokenizer(label, "\n");
    num_lines = t.countTokens();
    lines = new String[num_lines];
    line_widths = new int[num_lines];
    for (int i = 0; i < num_lines; i++)
      lines[i] = t.nextToken();
  }
  /**
   * This internal method figures out how the font is, and how wide each line of
   * the label is, and how wide the widest line is.
   */
  protected synchronized void measure() {
    FontMetrics fm = this.getFontMetrics(this.getFont());
    line_height = fm.getHeight();
    line_ascent = fm.getAscent();
    max_width = 0;
    for (int i = 0; i < num_lines; i++) {
      line_widths[i] = fm.stringWidth(lines[i]);
      if (line_widths[i] > max_width)
        max_width = line_widths[i];
    }
    measured = true;
  }
}
class AnswerEvent extends java.util.EventObject {
  public static final int YES = 0, NO = 1, CANCEL = 2; // Button constants
  protected int id; // Which button was pressed?
  public AnswerEvent(Object source, int id) {
    super(source);
    this.id = id;
  }
  public int getID() {
    return id;
  } // Return the button
}
interface AnswerListener extends java.util.EventListener {
  public void yes(AnswerEvent e);
  public void no(AnswerEvent e);
  public void cancel(AnswerEvent e);
}
/**
 * This JavaBean displays a multi-line message and up to three buttons. It fires
 * an AnswerEvent when the user clicks on one of the buttons
 */
public class YesNoPanel extends JPanel {
  // Properties of the bean.
  protected String messageText; // The message to display
  protected Alignment alignment; // The alignment of the message
  protected String yesLabel; // Text for the yes, no, & cancel buttons
  protected String noLabel;
  protected String cancelLabel;
  // Internal components of the panel
  protected MultiLineLabel message;
  protected JPanel buttonbox;
  protected JButton yes, no, cancel;
  /** The no-argument bean constructor, with default property values */
  public YesNoPanel() {
    this("Your\nMessage\nHere");
  }
  public YesNoPanel(String messageText) {
    this(messageText, Alignment.LEFT, "Yes", "No", "Cancel");
  }
  /** A constructor for programmers using this class "by hand" */
  public YesNoPanel(String messageText, Alignment alignment, String yesLabel, String noLabel,
      String cancelLabel) {
    // Create the components for this panel
    setLayout(new BorderLayout(15, 15));
    // Put the message label in the middle of the window.
    message = new MultiLineLabel(messageText, 20, 20, alignment);
    message.setOpaque(false); // allow background color to show through
    add(message, BorderLayout.CENTER);
    // Create a panel for the Panel buttons and put it at the bottom
    // of the Panel. Specify a FlowLayout layout manager for it.
    buttonbox = new JPanel();
    buttonbox.setLayout(new FlowLayout(FlowLayout.CENTER, 25, 15));
    buttonbox.setOpaque(false); // allow background color to show through
    add(buttonbox, BorderLayout.SOUTH);
    // Create each specified button, specifying the action listener
    // and action command for each, and adding them to the buttonbox
    yes = new JButton(); // Create buttons
    no = new JButton();
    cancel = new JButton();
    // Add the buttons to the button box
    buttonbox.add(yes);
    buttonbox.add(no);
    buttonbox.add(cancel);
    // Register listeners for each button
    yes.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        fireEvent(new AnswerEvent(YesNoPanel.this, AnswerEvent.YES));
      }
    });
    no.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        fireEvent(new AnswerEvent(YesNoPanel.this, AnswerEvent.NO));
      }
    });
    cancel.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        fireEvent(new AnswerEvent(YesNoPanel.this, AnswerEvent.CANCEL));
      }
    });
    // Now call property setter methods to set the message and button
    // components to contain the right text
    setMessageText(messageText);
    setAlignment(alignment);
    setYesLabel(yesLabel);
    setNoLabel(noLabel);
    setCancelLabel(cancelLabel);
  }
  // Methods to query all of the bean properties.
  public String getMessageText() {
    return messageText;
  }
  public Alignment getAlignment() {
    return alignment;
  }
  public String getYesLabel() {
    return yesLabel;
  }
  public String getNoLabel() {
    return noLabel;
  }
  public String getCancelLabel() {
    return cancelLabel;
  }
  public Font getMessageFont() {
    return message.getFont();
  }
  public Color getMessageColor() {
    return message.getForeground();
  }
  public Font getButtonFont() {
    return yes.getFont();
  }
  // Methods to set all of the bean properties.
  public void setMessageText(String messageText) {
    this.messageText = messageText;
    message.setLabel(messageText);
  }
  public void setAlignment(Alignment alignment) {
    this.alignment = alignment;
    message.setAlignment(alignment);
  }
  public void setYesLabel(String l) {
    yesLabel = l;
    yes.setText(l);
    yes.setVisible((l != null) && (l.length() > 0));
  }
  public void setNoLabel(String l) {
    noLabel = l;
    no.setText(l);
    no.setVisible((l != null) && (l.length() > 0));
  }
  public void setCancelLabel(String l) {
    cancelLabel = l;
    cancel.setText(l);
    cancel.setVisible((l != null) && (l.length() > 0));
  }
  public void setMessageFont(Font f) {
    message.setFont(f);
  }
  public void setMessageColor(Color c) {
    message.setForeground(c);
  }
  public void setButtonFont(Font f) {
    yes.setFont(f);
    no.setFont(f);
    cancel.setFont(f);
  }
  /** This field holds a list of registered ActionListeners. */
  protected List listeners = new ArrayList();
  /** Register an action listener to be notified when a button is pressed */
  public void addAnswerListener(AnswerListener l) {
    listeners.add(l);
  }
  /** Remove an Answer listener from our list of interested listeners */
  public void removeAnswerListener(AnswerListener l) {
    listeners.remove(l);
  }
  /** Send an event to all registered listeners */
  public void fireEvent(AnswerEvent e) {
    // Make a copy of the list and fire the events using that copy.
    // This means that listeners can be added or removed from the original
    // list in response to this event.
    Object[] copy = listeners.toArray();
    for (int i = 0; i < copy.length; i++) {
      AnswerListener listener = (AnswerListener) copy[i];
      switch (e.getID()) {
      case AnswerEvent.YES:
        listener.yes(e);
        break;
      case AnswerEvent.NO:
        listener.no(e);
        break;
      case AnswerEvent.CANCEL:
        listener.cancel(e);
        break;
      }
    }
  }
  /** A main method that demonstrates the class */
  public static void main(String[] args) {
    // Create an instance of YesNoPanel, with title and message specified:
    YesNoPanel p = new YesNoPanel("Do you really want to quit?");
    // Register an action listener for the Panel. This one just prints
    // the results out to the console.
    p.addAnswerListener(new AnswerListener() {
      public void yes(AnswerEvent e) {
        System.exit(0);
      }
      public void no(AnswerEvent e) {
        System.out.println("No");
      }
      public void cancel(AnswerEvent e) {
        System.out.println("Cancel");
      }
    });
    JFrame f = new JFrame();
    f.getContentPane().add(p);
    f.pack();
    f.setVisible(true);
  }
}