Strokes


The draw operation of the Graphics2D class draws the boundary of a shape by using the currently selected stroke. By default, the stroke is a solid line that is one pixel wide. You can select a different stroke by calling the setStroke method. You supply an object of a class that implements the Stroke interface. The Java 2D API defines only one such class, called BasicStroke. In this section, we look at the capabilities of the BasicStroke class.

You can construct strokes of arbitrary thickness. For example, here is how you draw lines that are 10 pixels wide.

 g2.setStroke(new BasicStroke(10.0F)); g2.draw(new Line2D.Double(. . .)); 

When a stroke is more than a pixel thick, then the end of the stroke can have different styles. Figure 7-12 shows these so-called end cap styles. You have three choices:

  • A butt cap simply ends the stroke at its end point.

  • A round cap adds a half-circle to the end of the stroke.

  • A square cap adds a half-square to the end of the stroke.

Figure 7-12. End cap styles


When two thick strokes meet, there are three choices for the join style (see Figure 7-13).

  • A bevel join joins the strokes with a straight line that is perpendicular to the bisector of the angle between the two strokes.

  • A round join extends each stroke to have a round cap.

  • A miter join extends both strokes by adding a "spike."

Figure 7-13. Join styles


The miter join is not suitable for lines that meet at small angles. If two lines join with an angle that is less than the miter limit, then a bevel join is used instead. That usage prevents extremely long spikes. By default, the miter limit is 10 degrees.

You specify these choices in the BasicStroke constructor, for example:

 g2.setStroke(new BasicStroke(10.0F, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setStroke(new BasicStroke(10.0F, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,    15.0F /* miter limit */)); 

Finally, you can specify dashed lines by setting a dash pattern. In the program in Example 7-3, you can select a dash pattern that spells out SOS in Morse code. The dash pattern is a float[] array of numbers that contains the lengths of the "on" and "off" strokes (see Figure 7-14).

Figure 7-14. A dash pattern


You specify the dash pattern and a dash phase when constructing the BasicStroke. The dash phase indicates where in the dash pattern each line should start. Normally, you set this value to 0.

 float[] dashPattern = { 10, 10, 10, 10, 10, 10, 30, 10, 30, ... }; g2.setStroke(new BasicStroke(10.0F, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,    10.0F /* miter limit */, dashPattern, 0 /* dash phase */)); 

NOTE

End cap styles are applied to the ends of each dash in a dash pattern.


The program in Example 7-3 lets you specify end cap styles, join styles, and dashed lines (see Figure 7-15). You can move the ends of the line segments to test the miter limit: Select the miter join, then move the line segment to form a very acute angle. You will see the miter join turn into a bevel join.

Figure 7-15. The StrokeTest program


The program is similar to the program in Example 7-1. The mouse listener remembers if you click on the end point of a line segment, and the mouse motion listener monitors the dragging of the end point. A set of radio buttons signal the user choices for the end cap style, join style, and solid or dashed line. The paintComponent method of the StrokePanel class constructs a GeneralPath consisting of the two line segments that join the three points that the user can move with the mouse. It then constructs a BasicStroke, according to the selections that the user made, and finally draws the path.

Example 7-3. StrokeTest.java
   1. import java.awt.*;   2. import java.awt.event.*;   3. import java.awt.geom.*;   4. import java.util.*;   5. import javax.swing.*;   6.   7. /**   8.    This program demonstrates different stroke types.   9. */  10. public class StrokeTest  11. {  12.    public static void main(String[] args)  13.    {  14.       JFrame frame = new StrokeTestFrame();  15.       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  16.       frame.setVisible(true);  17.    }  18. }  19.  20. /**  21.    This frame lets the user choose the cap, join, and  22.    line style, and shows the resulting stroke.  23. */  24. class StrokeTestFrame extends JFrame  25. {  26.    public StrokeTestFrame()  27.    {  28.       setTitle("StrokeTest");  29.       setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);  30.  31.       canvas = new StrokePanel();  32.       add(canvas, BorderLayout.CENTER);  33.  34.       buttonPanel = new JPanel();  35.       buttonPanel.setLayout(new GridLayout(3, 3));  36.       add(buttonPanel, BorderLayout.NORTH);  37.  38.       ButtonGroup group1 = new ButtonGroup();  39.       makeCapButton("Butt Cap", BasicStroke.CAP_BUTT, group1);  40.       makeCapButton("Round Cap", BasicStroke.CAP_ROUND, group1);  41.       makeCapButton("Square Cap", BasicStroke.CAP_SQUARE, group1);  42.  43.       ButtonGroup group2 = new ButtonGroup();  44.       makeJoinButton("Miter Join", BasicStroke.JOIN_MITER, group2);  45.       makeJoinButton("Bevel Join", BasicStroke.JOIN_BEVEL, group2);  46.       makeJoinButton("Round Join", BasicStroke.JOIN_ROUND, group2);  47.  48.       ButtonGroup group3 = new ButtonGroup();  49.       makeDashButton("Solid Line", false, group3);  50.       makeDashButton("Dashed Line", true, group3);  51.    }  52.  53.    /**  54.       Makes a radio button to change the cap style.  55.       @param label the button label  56.       @param style the cap style  57.       @param group the radio button group  58.    */  59.    private void makeCapButton(String label, final int style, ButtonGroup group)  60.    {  61.       // select first button in group  62.       boolean selected = group.getButtonCount() == 0;  63.       JRadioButton button = new JRadioButton(label, selected);  64.       buttonPanel.add(button);  65.       group.add(button);  66.       button.addActionListener(new  67.          ActionListener()  68.          {  69.             public void actionPerformed(ActionEvent event)  70.             {  71.                canvas.setCap(style);  72.             }  73.          });  74.    }  75.  76.    /**  77.       Makes a radio button to change the join style.  78.       @param label the button label  79.       @param style the join style  80.       @param group the radio button group  81.    */  82.    private void makeJoinButton(String label, final int style,  83.       ButtonGroup group)  84.    {  85.       // select first button in group  86.       boolean selected = group.getButtonCount() == 0;  87.       JRadioButton button = new JRadioButton(label, selected);  88.       buttonPanel.add(button);  89.       group.add(button);  90.       button.addActionListener(new  91.          ActionListener()  92.          {  93.             public void actionPerformed(ActionEvent event)  94.             {  95.                canvas.setJoin(style);  96.             }  97.          });  98.    }  99. 100.    /** 101.       Makes a radio button to set solid or dashed lines 102.       @param label the button label 103.       @param style false for solid, true for dashed lines 104.       @param group the radio button group 105.    */ 106.    private void makeDashButton(String label, final boolean style, 107.       ButtonGroup group) 108.    { 109.       // select first button in group 110.       boolean selected = group.getButtonCount() == 0; 111.       JRadioButton button = new JRadioButton(label, selected); 112.       buttonPanel.add(button); 113.       group.add(button); 114.       button.addActionListener(new 115.          ActionListener() 116.          { 117.             public void actionPerformed(ActionEvent event) 118.             { 119.                canvas.setDash(style); 120.             } 121.          }); 122.    } 123. 124.    private StrokePanel canvas; 125.    private JPanel buttonPanel; 126. 127.    private static final int DEFAULT_WIDTH = 400; 128.    private static final int DEFAULT_HEIGHT = 400; 129. } 130. 131. /** 132.    This panel draws two joined lines, using different 133.    stroke objects, and allows the user to drag the three 134.    points defining the lines. 135. */ 136. class StrokePanel extends JPanel 137. { 138.    public StrokePanel() 139.    { 140.       addMouseListener(new 141.          MouseAdapter() 142.          { 143.             public void mousePressed(MouseEvent event) 144.             { 145.                Point p = event.getPoint(); 146.                for (int i = 0; i < points.length; i++) 147.                { 148.                   double x = points[i].getX() - SIZE / 2; 149.                   double y = points[i].getY() - SIZE / 2; 150.                   Rectangle2D r = new Rectangle2D.Double(x, y, SIZE, SIZE); 151.                   if (r.contains(p)) 152.                   { 153.                      current = i; 154.                      return; 155.                   } 156.                } 157.             } 158. 159.             public void mouseReleased(MouseEvent event) 160.             { 161.                current = -1; 162.             } 163.          }); 164. 165.       addMouseMotionListener(new 166.          MouseMotionAdapter() 167.          { 168.             public void mouseDragged(MouseEvent event) 169.             { 170.                if (current == -1) return; 171.                points[current] = event.getPoint(); 172.                repaint(); 173.             } 174.          }); 175. 176.       points = new Point2D[3]; 177.       points[0] = new Point2D.Double(200, 100); 178.       points[1] = new Point2D.Double(100, 200); 179.       points[2] = new Point2D.Double(200, 200); 180.       current = -1; 181.       width = 8.0F; 182.    } 183. 184.    public void paintComponent(Graphics g) 185.    { 186.       super.paintComponent(g); 187.       Graphics2D g2 = (Graphics2D) g; 188.       GeneralPath path = new GeneralPath(); 189.       path.moveTo((float) points[0].getX(), (float) points[0].getY()); 190.       for (int i = 1; i < points.length; i++) 191.          path.lineTo((float) points[i].getX(), (float) points[i].getY()); 192.       BasicStroke stroke; 193.       if (dash) 194.       { 195.          float miterLimit = 10.0F; 196.          float[] dashPattern = { 10F, 10F, 10F, 10F, 10F, 10F, 197.             30F, 10F, 30F, 10F, 30F, 10F, 10F, 10F, 10F, 10F, 10F, 30F }; 198.          float dashPhase = 0; 199.          stroke = new BasicStroke(width, cap, join, miterLimit, dashPattern, dashPhase); 200.       } 201.       else 202.          stroke = new BasicStroke(width, cap, join); 203.       g2.setStroke(stroke); 204.       g2.draw(path); 205.    } 206. 207.    /** 208.       Sets the join style. 209.       @param j the join style 210.    */ 211.    public void setJoin(int j) 212.    { 213.       join = j; 214.       repaint(); 215.    } 216. 217.    /** 218.       Sets the cap style. 219.       @param c the cap style 220.    */ 221.    public void setCap(int c) 222.    { 223.       cap = c; 224.       repaint(); 225.    } 226. 227.    /** 228.       Sets solid or dashed lines 229.       @param d false for solid, true for dashed lines 230.    */ 231.    public void setDash(boolean d) 232.    { 233.       dash = d; 234.       repaint(); 235.    } 236. 237.    private Point2D[] points; 238.    private static int SIZE = 10; 239.    private int current; 240.    private float width; 241.    private int cap; 242.    private int join; 243.    private boolean dash; 244. } 


 java.awt.Graphics2D 1.2 

  • void setStroke(Stroke s)

    sets the stroke of this graphics context to the given object that implements the Stroke interface.


 java.awt.BasicStroke 1.2 

  • BasicStroke(float width)

  • BasicStroke(float width, int cap, int join)

  • BasicStroke(float width, int cap, int join, float miterlimit)

  • BasicStroke(float width, int cap, int join, float miterlimit, float[] dash, float dashPhase)

    construct a stroke object with the given attributes.

    Parameters:

    width

    The width of the pen

     

    cap

    The end cap style, one of CAP_BUTT, CAP_ROUND, and CAP_SQUARE

     

    join

    The join style, one of JOIN_BEVEL, JOIN_MITER, and JOIN_ROUND

     

    miterlimit

    The angle, in degrees, below which a miter join is rendered as a bevel join

     

    dash

    An array of the lengths of the alternating filled and blank portions of a dashed stroke

     

    dashPhase

    The "phase" of the dash pattern; a segment of this length, preceding the starting point of the stroke, is assumed to have the dash pattern already applied




    Core JavaT 2 Volume II - Advanced Features
    Building an On Demand Computing Environment with IBM: How to Optimize Your Current Infrastructure for Today and Tomorrow (MaxFacts Guidebook series)
    ISBN: 193164411X
    EAN: 2147483647
    Year: 2003
    Pages: 156
    Authors: Jim Hoskins

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net