Java/Swing Components/Panel
Версия от 18:01, 31 мая 2010; (обсуждение)
Содержание
- 1 A basic panel that displays a small up or down arrow.
- 2 A JPanel with a textured background.
- 3 Gradient Panel
- 4 Graph Canvas
- 5 Swing Panel Group
- 6 Swing Panel Group 2
- 7 Time panel shows the current time.
- 8 Transfer focus from button to button with help of arrows keys.
- 9 Transparent Panel
- 10 Yes / No Panel
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);
}
}