|
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:
Figure 7-12. End cap stylesWhen two thick strokes meet, there are three choices for the join style (see Figure 7-13).
Figure 7-13. Join stylesThe 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 patternYou 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
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 programThe 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.java1. 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
java.awt.BasicStroke 1.2
|
|