Home Segments Top Top Previous Next

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