// This example is from the book "Java in a Nutshell, Second Edition".
// Written by David Flanagan. Copyright (c) 1997 O'Reilly & Associates.
// You may distribute this source code for non-commercial purposes only.
// You may study, modify, and use this example for any purpose, as long as
// this notice is retained. Note that this example is provided "as is",
// WITHOUT WARRANTY of any kind either expressed or implied.
package oreilly.beans.yesno;
import java.awt.*;
import java.util.*;
/**
* A custom component that displays multiple lines of text with specified
* margins and alignment. In Java 1.1, we could extend Component instead
* of Canvas, making this a more efficient "Lightweight component"
*/
public class MultiLineLabel extends Canvas {
// User-specified attributes
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 int alignment; // The alignment of the text.
public static final int LEFT = 0, CENTER = 1, RIGHT = 2; // alignment values
// 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, int 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, LEFT);
}
public MultiLineLabel(String label, int alignment) {
this(label, 10, 10, alignment);
}
public MultiLineLabel(String label) { this(label, 10, 10, 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.
measured = false; // Note that we need to measure lines.
repaint(); // Request a redraw.
}
public void setFont(Font f) {
super.setFont(f); // Tell our superclass about the new font.
measured = false; // Note that we need to remeasure lines.
repaint(); // Request a redraw.
}
public void setForeground(Color c) {
super.setForeground(c); // Tell our superclass about the new color.
repaint(); // Request a redraw (size is unchanged).
}
public void setAlignment(int a) { alignment = a; repaint(); }
public void setMarginWidth(int mw) { margin_width = mw; repaint(); }
public void setMarginHeight(int mh) { margin_height = mh; repaint(); }
public String getLabel() { return label; }
public int 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. In Java 1.1, getPreferredSize() is
* the preferred version of this method. We use this deprecated version
* so that this component can interoperate with 1.0 components.
*/
public Dimension preferredSize() {
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.
* For Java 1.1, we'd use getMinimumSize().
*/
public Dimension minimumSize() { return preferredSize(); }
/**
* This method draws the label (same method that applets use).
* 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 paint(Graphics g) {
int x, y;
Dimension size = this.size(); // use getSize() in Java 1.1
if (!measured) measure();
y = line_ascent + (size.height - num_lines * line_height)/2;
for(int i = 0; i < num_lines; i++, y += line_height) {
switch(alignment) {
default:
case LEFT: x = margin_width; break;
case CENTER: x = (size.width - line_widths[i])/2; break;
case RIGHT: x = size.width - margin_width - line_widths[i]; break;
}
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.getToolkit().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;
}
}
|