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);} }