![]() |
![]() |
![]() |
![]() |
![]() |
|
Appendix B: | The Meter Canvas |
The following Meter class is used in
examples in this book. The definition includes statements that illustrate
how you draw elements, such as lines, arcs, and triangles:
import java.awt.*;
import javax.swing.*;
import java.util.*;
public class Meter extends JComponent implements MeterInterface {
String title = "Title to Be Supplied"; // Title string for the meter
int minimum, maximum; // Minimum and maximum values displayed
int value; // Currently displayed value
static int border = 10; // Minimum space between dial and frame
int yOffset; // Gap at the bottom
int xCenter; // Center of pointer
int yCenter; // Center of pointer
int radius; // Radius of dial circle
// Two-parameter constructor takes arguments specifying the
// the minimum and maximum values that the meter displays:
public Meter (int x, int y) {
minimum = x;
maximum = y;
value = (x + y) / 2;
}
// Title setter:
public void setTitle(String s) {title = s; repaint();}
// Value setter:
public void setValue(int v) {
// If the value is less than the minimum, set to minimum:
if (v < minimum) {value = minimum;}
// If the value is greater than the maximum, set to maximum:
else if (v > maximum) {value = maximum;}
else {value = v;}
repaint();
}
public int getValueAtCoordinates (int x, int y) {
Dimension d = getSize();
xCenter = (int)(d.width / 2);
yOffset = (int)(d.height / 4);
yCenter = (int)(d.height - yOffset);
double angle = Math.atan2(x - xCenter, yCenter - y) + (Math.PI / 2);
double fraction = angle / Math.PI;
return (int)Math.round(fraction * (maximum - minimum) + minimum);
}
// Draw the tick marks associated with the meter:
// Write the title associated with the meter, centered at bottom:
// Paint, by calling other methods:
public void paint(Graphics g) {
computeKeyValues();
Dimension d = getSize();
drawTics(g);
drawText(g);
drawPointer(g);
}
// Perform miscellaneous chores
private void computeKeyValues () {
Dimension d = getSize();
xCenter = (int)(d.width / 2);
yOffset = (int)(d.height / 4);
yCenter = (int)(d.height - yOffset);
radius = Math.min(xCenter, yCenter) - (2 * border);
}
private void drawTics(Graphics g) {
double angleDelta = Math.PI / 50.0;
double angle = 0.0;
int innerRadius = (int)(radius - (radius / 10));
int middleRadius = (int)(radius - (radius / 20));
// Draw an arc on which to draw the tics:
g.drawArc(xCenter - radius,
yCenter - radius,
radius * 2,
radius * 2, 0, 180);
// Draw about 50 tick marks with about 10 major ticks
for (int i=0; i<=50; i++, angle += angleDelta) {
double cosAngle = Math.cos(angle);
double sinAngle = Math.sin(angle);
int x1, x2, y1, y2;
x1 = (int)(radius * cosAngle) + xCenter;
y1 = yCenter - (int)(radius * sinAngle);
if (i%5 == 0) {
x2 = (int)(innerRadius * cosAngle) + xCenter;
y2 = yCenter - (int)(innerRadius * sinAngle);
}
else {
x2 = (int)(middleRadius * cosAngle) + xCenter;
y2 = yCenter - (int)(middleRadius * sinAngle);
}
g.drawLine(x1, y1, x2, y2);
}
}
private void drawText(Graphics g) {
Dimension d = getSize();
// Prepare font
int fontSize = Math.max(12, d.width / 30);
g.setFont(new Font("Helvetica", Font.BOLD, fontSize));
// Write title:
FontMetrics f = g.getFontMetrics();
int stringWidth = f.stringWidth(title);
int textXOffset = (d.width - stringWidth) / 2;
int textYOffset = (3 * d.height / 4) + (2 * f.getHeight());
g.drawString(title, textXOffset, textYOffset);
// Set minimum and maximum values
int fontHeight = f.getHeight();
int fontDescent = f.getDescent();
int middleRadius = (int)(radius - (radius / 20));
String sval = String.valueOf(minimum);
stringWidth = f.stringWidth(sval);
// Draw the minimum-value string:
g.drawString(sval,
xCenter - middleRadius + 10,
yCenter - fontDescent);
sval = String.valueOf(maximum);
stringWidth = f.stringWidth(sval);
// Draw the maximum-value string:
g.drawString(sval,
xCenter + middleRadius - stringWidth - 10,
yCenter - fontDescent);
}
private void drawPointer(Graphics g) {
// Compute the angle dictated by the value;
// Increase the angle from left to right:
double angle = ((double)(value - minimum)
/ (double)(maximum - minimum)) * Math.PI;
// Measure from left to right
angle = Math.PI - angle;
double cosAngle = Math.cos(angle);
double sinAngle = Math.sin(angle);
// Compute coordinates of pointer's point
int xPoint = (int)(radius * cosAngle);
int yPoint = (int)(radius * sinAngle);
// Compute miscellaneous values
int pointerLength = (int) (1.1 * radius);
int pointerHalfWidth = (int) (pointerLength / 20);
int ovalRadius = (int) (pointerHalfWidth * 1.5);
// Obtain current Color instance:
Color colorHandle = g.getColor();
// Reset color temporarily:
g.setColor(Color.gray);
// Draw the circle
g.fillOval(xCenter - ovalRadius,
yCenter - ovalRadius,
2 * ovalRadius,
2 * ovalRadius);
// Compute the points on the pointer border;
// note that y increases downward
int xpoints[] = new int[3];
int ypoints[] = new int[3];
xpoints[0] = xPoint + xCenter;
ypoints[0] = yCenter - yPoint;
xpoints[1] = xPoint
- (int)(pointerLength * cosAngle)
- (int)(pointerHalfWidth * sinAngle) + xCenter;
ypoints[1] = yCenter
- (yPoint - (int )(pointerLength * sinAngle)
+ (int)(pointerHalfWidth * cosAngle));
xpoints[2] = xPoint
- (int)(pointerLength * cosAngle)
+ (int)(pointerHalfWidth * sinAngle) + xCenter;
ypoints[2] = yCenter
- (yPoint - (int)(pointerLength * sinAngle)
- (int)(pointerHalfWidth * cosAngle));
// Draw the pointer
g.fillPolygon(xpoints, ypoints, 3);
// Restore color:
g.setColor(colorHandle);
}
// Assist in sizing:
public Dimension getMinimumSize() {return new Dimension(200, 200);}
public Dimension getPreferredSize() {return new Dimension(200, 200);}
}