控制台程序。
为了与Sketcher中的其他元素类型保持一致,需要为Elements菜单添加Text菜单项和工具栏按钮。还需要定义用来表示文本元素的类Element.Text。
1、修改SketcherFrame类添加文本定义菜单项和工具栏按钮:
1 // Frame for the Sketcher application 2 import javax.swing.*; 3 import javax.swing.border.*; 4 import java.awt.event.*; 5 import java.awt.*; 6 7 import static java.awt.event.InputEvent.*; 8 import static java.awt.Color.*; 9 import static Constants.SketcherConstants.*; 10 import static javax.swing.Action.*; 11 12 @SuppressWarnings("serial") 13 public class SketcherFrame extends JFrame implements ActionListener { 14 // Constructor 15 public SketcherFrame(String title, Sketcher theApp) { 16 setTitle(title); // Set the window title 17 this.theApp = theApp; // Save app. object reference 18 setJMenuBar(menuBar); // Add the menu bar to the window 19 setDefaultCloseOperation(EXIT_ON_CLOSE); // Default is exit the application 20 21 createFileMenu(); // Create the File menu 22 createElementMenu(); // Create the element menu 23 createColorMenu(); // Create the element menu 24 createToolbar(); 25 toolBar.setRollover(true); 26 27 JMenu helpMenu = new JMenu("Help"); // Create Help menu 28 helpMenu.setMnemonic('H'); // Create Help shortcut 29 30 // Add the About item to the Help menu 31 aboutItem = new JMenuItem("About"); // Create About menu item 32 aboutItem.addActionListener(this); // Listener is the frame 33 helpMenu.add(aboutItem); // Add item to menu 34 menuBar.add(helpMenu); // Add Help menu to menu bar 35 36 getContentPane().add(toolBar, BorderLayout.NORTH); // Add the toolbar 37 getContentPane().add(statusBar, BorderLayout.SOUTH); // Add the statusbar 38 } 39 40 // Create File menu item actions 41 private void createFileMenuActions() { 42 newAction = new FileAction("New", 'N', CTRL_DOWN_MASK); 43 openAction = new FileAction("Open", 'O', CTRL_DOWN_MASK); 44 closeAction = new FileAction("Close"); 45 saveAction = new FileAction("Save", 'S', CTRL_DOWN_MASK); 46 saveAsAction = new FileAction("Save As..."); 47 printAction = new FileAction("Print", 'P', CTRL_DOWN_MASK); 48 exitAction = new FileAction("Exit", 'X', CTRL_DOWN_MASK); 49 50 // Initialize the array 51 FileAction[] actions = {openAction, closeAction, saveAction, saveAsAction, printAction, exitAction}; 52 fileActions = actions; 53 54 // Add toolbar icons 55 newAction.putValue(LARGE_ICON_KEY, NEW24); 56 openAction.putValue(LARGE_ICON_KEY, OPEN24); 57 saveAction.putValue(LARGE_ICON_KEY, SAVE24); 58 saveAsAction.putValue(LARGE_ICON_KEY, SAVEAS24); 59 printAction.putValue(LARGE_ICON_KEY, PRINT24); 60 61 // Add menu item icons 62 newAction.putValue(SMALL_ICON, NEW16); 63 openAction.putValue(SMALL_ICON, OPEN16); 64 saveAction.putValue(SMALL_ICON, SAVE16); 65 saveAsAction.putValue(SMALL_ICON,SAVEAS16); 66 printAction.putValue(SMALL_ICON, PRINT16); 67 68 // Add tooltip text 69 newAction.putValue(SHORT_DESCRIPTION, "Create a new sketch"); 70 openAction.putValue(SHORT_DESCRIPTION, "Read a sketch from a file"); 71 closeAction.putValue(SHORT_DESCRIPTION, "Close the current sketch"); 72 saveAction.putValue(SHORT_DESCRIPTION, "Save the current sketch to file"); 73 saveAsAction.putValue(SHORT_DESCRIPTION, "Save the current sketch to a new file"); 74 printAction.putValue(SHORT_DESCRIPTION, "Print the current sketch"); 75 exitAction.putValue(SHORT_DESCRIPTION, "Exit Sketcher"); 76 } 77 78 // Create the File menu 79 private void createFileMenu() { 80 JMenu fileMenu = new JMenu("File"); // Create File menu 81 fileMenu.setMnemonic('F'); // Create shortcut 82 createFileMenuActions(); // Create Actions for File menu item 83 84 // Construct the file drop-down menu 85 fileMenu.add(newAction); // New Sketch menu item 86 fileMenu.add(openAction); // Open sketch menu item 87 fileMenu.add(closeAction); // Close sketch menu item 88 fileMenu.addSeparator(); // Add separator 89 fileMenu.add(saveAction); // Save sketch to file 90 fileMenu.add(saveAsAction); // Save As menu item 91 fileMenu.addSeparator(); // Add separator 92 fileMenu.add(printAction); // Print sketch menu item 93 fileMenu.addSeparator(); // Add separator 94 fileMenu.add(exitAction); // Print sketch menu item 95 menuBar.add(fileMenu); // Add the file menu 96 } 97 98 // Create Element menu actions 99 private void createElementTypeActions() { 100 lineAction = new TypeAction("Line", LINE, 'L', CTRL_DOWN_MASK); 101 rectangleAction = new TypeAction("Rectangle", RECTANGLE, 'R', CTRL_DOWN_MASK); 102 circleAction = new TypeAction("Circle", CIRCLE,'C', CTRL_DOWN_MASK); 103 curveAction = new TypeAction("Curve", CURVE,'U', CTRL_DOWN_MASK); 104 textAction = new TypeAction("Text", TEXT,'T', CTRL_DOWN_MASK); 105 106 // Initialize the array 107 TypeAction[] actions = {lineAction, rectangleAction, circleAction, curveAction, textAction}; 108 typeActions = actions; 109 110 // Add toolbar icons 111 lineAction.putValue(LARGE_ICON_KEY, LINE24); 112 rectangleAction.putValue(LARGE_ICON_KEY, RECTANGLE24); 113 circleAction.putValue(LARGE_ICON_KEY, CIRCLE24); 114 curveAction.putValue(LARGE_ICON_KEY, CURVE24); 115 textAction.putValue(LARGE_ICON_KEY, TEXT24); 116 117 // Add menu item icons 118 lineAction.putValue(SMALL_ICON, LINE16); 119 rectangleAction.putValue(SMALL_ICON, RECTANGLE16); 120 circleAction.putValue(SMALL_ICON, CIRCLE16); 121 curveAction.putValue(SMALL_ICON, CURVE16); 122 textAction.putValue(SMALL_ICON, TEXT16); 123 124 // Add tooltip text 125 lineAction.putValue(SHORT_DESCRIPTION, "Draw lines"); 126 rectangleAction.putValue(SHORT_DESCRIPTION, "Draw rectangles"); 127 circleAction.putValue(SHORT_DESCRIPTION, "Draw circles"); 128 curveAction.putValue(SHORT_DESCRIPTION, "Draw curves"); 129 textAction.putValue(SHORT_DESCRIPTION, "Draw text"); 130 } 131 132 // Create the Elements menu 133 private void createElementMenu() { 134 createElementTypeActions(); 135 elementMenu = new JMenu("Elements"); // Create Elements menu 136 elementMenu.setMnemonic('E'); // Create shortcut 137 createRadioButtonDropDown(elementMenu, typeActions, lineAction); 138 menuBar.add(elementMenu); // Add the element menu 139 } 140 141 // Create Color menu actions 142 private void createElementColorActions() { 143 redAction = new ColorAction("Red", RED, 'R', CTRL_DOWN_MASK|ALT_DOWN_MASK); 144 yellowAction = new ColorAction("Yellow", YELLOW, 'Y', CTRL_DOWN_MASK|ALT_DOWN_MASK); 145 greenAction = new ColorAction("Green", GREEN, 'G', CTRL_DOWN_MASK|ALT_DOWN_MASK); 146 blueAction = new ColorAction("Blue", BLUE, 'B', CTRL_DOWN_MASK|ALT_DOWN_MASK); 147 148 // Initialize the array 149 ColorAction[] actions = {redAction, greenAction, blueAction, yellowAction}; 150 colorActions = actions; 151 152 // Add toolbar icons 153 redAction.putValue(LARGE_ICON_KEY, RED24); 154 greenAction.putValue(LARGE_ICON_KEY, GREEN24); 155 blueAction.putValue(LARGE_ICON_KEY, BLUE24); 156 yellowAction.putValue(LARGE_ICON_KEY, YELLOW24); 157 158 // Add menu item icons 159 redAction.putValue(SMALL_ICON, RED16); 160 greenAction.putValue(SMALL_ICON, GREEN16); 161 blueAction.putValue(SMALL_ICON, BLUE16); 162 yellowAction.putValue(SMALL_ICON, YELLOW16); 163 164 // Add tooltip text 165 redAction.putValue(SHORT_DESCRIPTION, "Draw in red"); 166 greenAction.putValue(SHORT_DESCRIPTION, "Draw in green"); 167 blueAction.putValue(SHORT_DESCRIPTION, "Draw in blue"); 168 yellowAction.putValue(SHORT_DESCRIPTION, "Draw in yellow"); 169 } 170 171 // Create the Color menu 172 private void createColorMenu() { 173 createElementColorActions(); 174 colorMenu = new JMenu("Color"); // Create Elements menu 175 colorMenu.setMnemonic('C'); // Create shortcut 176 createRadioButtonDropDown(colorMenu, colorActions, blueAction); 177 menuBar.add(colorMenu); // Add the color menu 178 } 179 180 // Menu creation helper 181 private void createRadioButtonDropDown(JMenu menu, Action[] actions, Action selected) { 182 ButtonGroup group = new ButtonGroup(); 183 JRadioButtonMenuItem item = null; 184 for(Action action : actions) { 185 group.add(menu.add(item = new JRadioButtonMenuItem(action))); 186 if(action == selected) { 187 item.setSelected(true); // This is default selected 188 } 189 } 190 } 191 192 // Create toolbar buttons on the toolbar 193 private void createToolbar() { 194 for(FileAction action: fileActions){ 195 if(action != exitAction && action != closeAction) 196 addToolbarButton(action); // Add the toolbar button 197 } 198 toolBar.addSeparator(); 199 200 // Create Color menu buttons 201 for(ColorAction action:colorActions){ 202 addToolbarButton(action); // Add the toolbar button 203 } 204 205 toolBar.addSeparator(); 206 207 // Create Elements menu buttons 208 for(TypeAction action:typeActions){ 209 addToolbarButton(action); // Add the toolbar button 210 } 211 } 212 213 // Create and add a toolbar button 214 private void addToolbarButton(Action action) { 215 JButton button = new JButton(action); // Create from Action 216 button.setBorder(BorderFactory.createCompoundBorder( // Add button border 217 new EmptyBorder(2,5,5,2), // Outside border 218 BorderFactory.createRaisedBevelBorder())); // Inside border 219 button.setHideActionText(true); // No label on the button 220 toolBar.add(button); // Add the toolbar button 221 } 222 223 // Return the current drawing color 224 public Color getElementColor() { 225 return elementColor; 226 } 227 228 // Return the current element type 229 public int getElementType() { 230 return elementType; 231 } 232 233 // Return current text font 234 public Font getFont() { 235 return textFont; 236 } 237 238 // Set radio button menu checks 239 private void setChecks(JMenu menu, Object eventSource) { 240 if(eventSource instanceof JButton){ 241 JButton button = (JButton)eventSource; 242 Action action = button.getAction(); 243 for(int i = 0 ; i<menu.getItemCount() ; ++i) { 244 JMenuItem item = menu.getItem(i); 245 item.setSelected(item.getAction() == action); 246 } 247 } 248 } 249 250 // Handle About menu events 251 public void actionPerformed(ActionEvent e) { 252 if(e.getSource() == aboutItem) { 253 // Create about dialog with the app window as parent 254 JOptionPane.showMessageDialog(this, // Parent 255 "Sketcher Copyright Ivor Horton 2011", // Message 256 "About Sketcher", // Title 257 JOptionPane.INFORMATION_MESSAGE); // Message type 258 } 259 } 260 261 // Inner class defining Action objects for File menu items 262 class FileAction extends AbstractAction { 263 // Create action with a name 264 FileAction(String name) { 265 super(name); 266 } 267 268 // Create action with a name and accelerator 269 FileAction(String name, char ch, int modifiers) { 270 super(name); 271 putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(ch, modifiers)); 272 273 // Now find the character to underline 274 int index = name.toUpperCase().indexOf(ch); 275 if(index != -1) { 276 putValue(DISPLAYED_MNEMONIC_INDEX_KEY, index); 277 } 278 } 279 280 // Event handler 281 public void actionPerformed(ActionEvent e) { 282 // You will add action code here eventually... 283 } 284 } 285 286 // Inner class defining Action objects for Element type menu items 287 class TypeAction extends AbstractAction { 288 // Create action with just a name property 289 TypeAction(String name, int typeID) { 290 super(name); 291 this.typeID = typeID; 292 } 293 294 // Create action with a name and an accelerator 295 private TypeAction(String name,int typeID, char ch, int modifiers) { 296 this(name, typeID); 297 putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(ch, modifiers)); 298 299 // Now find the character to underline 300 int index = name.toUpperCase().indexOf(ch); 301 if(index != -1) { 302 putValue(DISPLAYED_MNEMONIC_INDEX_KEY, index); 303 } 304 } 305 306 public void actionPerformed(ActionEvent e) { 307 elementType = typeID; 308 setChecks(elementMenu, e.getSource()); 309 statusBar.setTypePane(typeID); 310 } 311 312 private int typeID; 313 } 314 315 // Handles color menu items 316 class ColorAction extends AbstractAction { 317 // Create an action with a name and a color 318 public ColorAction(String name, Color color) { 319 super(name); 320 this.color = color; 321 } 322 323 // Create an action with a name, a color, and an accelerator 324 public ColorAction(String name, Color color, char ch, int modifiers) { 325 this(name, color); 326 putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(ch, modifiers)); 327 328 // Now find the character to underline 329 int index = name.toUpperCase().indexOf(ch); 330 if(index != -1) { 331 putValue(DISPLAYED_MNEMONIC_INDEX_KEY, index); 332 } 333 } 334 335 public void actionPerformed(ActionEvent e) { 336 elementColor = color; 337 setChecks(colorMenu, e.getSource()); 338 statusBar.setColorPane(color); 339 } 340 341 private Color color; 342 } 343 344 // File actions 345 private FileAction newAction, openAction, closeAction, saveAction, saveAsAction, printAction, exitAction; 346 private FileAction[] fileActions; // File actions as an array 347 348 // Element type actions 349 private TypeAction lineAction, rectangleAction, circleAction, curveAction, textAction; 350 private TypeAction[] typeActions; // Type actions as an array 351 352 // Element color actions 353 private ColorAction redAction, yellowAction,greenAction, blueAction; 354 private ColorAction[] colorActions; // Color actions as an array 355 356 private JMenuBar menuBar = new JMenuBar(); // Window menu bar 357 private JMenu elementMenu; // Elements menu 358 private JMenu colorMenu; // Color menu 359 private StatusBar statusBar = new StatusBar(); // Window status bar 360 361 private JMenuItem aboutItem; // About menu item 362 363 private Color elementColor = DEFAULT_ELEMENT_COLOR; // Current element color 364 private int elementType = DEFAULT_ELEMENT_TYPE; // Current element type 365 private Font textFont = DEFAULT_FONT; // Default font for text elements 366 private JToolBar toolBar = new JToolBar(); // Window toolbar 367 private Sketcher theApp; // The application object 368 }
2、定义文本类:
1 import java.awt.*; 2 import java.io.Serializable; 3 import static Constants.SketcherConstants.*; 4 import java.awt.geom.*; 5 6 public abstract class Element implements Serializable{ 7 8 public Element(Point position, Color color) { 9 this.position = new Point(position); 10 this.color = color; 11 } 12 13 protected Element(Color color) { 14 this.color = color; 15 } 16 17 // Returns the color of the element 18 public Color getColor() { 19 return color; 20 } 21 22 // Returns the position of the element 23 public Point getPosition() { 24 return position; 25 } 26 27 // Returns the bounding rectangle enclosing an element boundary 28 public java.awt.Rectangle getBounds() { 29 return bounds; 30 } 31 32 // Create a new element 33 public static Element createElement(int type, Color color, Point start, Point end) { 34 switch(type) { 35 case LINE: 36 return new Element.Line(start, end, color); 37 case RECTANGLE: 38 return new Rectangle(start, end, color); 39 case CIRCLE: 40 return new Circle(start, end, color); 41 case CURVE: 42 return new Curve(start, end, color); 43 default: 44 assert false; // We should never get to here 45 } 46 return null; 47 } 48 49 // Nested class defining a line 50 public static class Line extends Element { 51 public Line(Point start, Point end, Color color) { 52 super(start, color); 53 line = new Line2D.Double(origin.x, origin.y, end.x - position.x, end.y - position.y); 54 bounds = new java.awt.Rectangle( 55 Math.min(start.x ,end.x), Math.min(start.y, end.y), 56 Math.abs(start.x - end.x)+1, Math.abs(start.y - end.y)+1); 57 } 58 59 // Change the end point for the line 60 public void modify(Point start, Point last) { 61 line.x2 = last.x - position.x; 62 line.y2 = last.y - position.y; 63 bounds = new java.awt.Rectangle( 64 Math.min(start.x ,last.x), Math.min(start.y, last.y), 65 Math.abs(start.x - last.x)+1, Math.abs(start.y - last.y)+1); 66 } 67 68 // Display the line 69 public void draw(Graphics2D g2D) { 70 g2D.setPaint(color); 71 g2D.translate(position.x, position.y); // Move context origin 72 g2D.draw(line); // Draw the line 73 g2D.translate(-position.x, -position.y); // Move context origin back 74 } 75 private Line2D.Double line; 76 protected boolean highlighted = false; // Highlight flag 77 private final static long serialVersionUID = 1001L; 78 } 79 80 // Nested class defining a rectangle 81 public static class Rectangle extends Element { 82 public Rectangle(Point start, Point end, Color color) { 83 super(new Point(Math.min(start.x, end.x), Math.min(start.y, end.y)), color); 84 rectangle = new Rectangle2D.Double( 85 origin.x, origin.y, // Top-left corner 86 Math.abs(start.x - end.x), Math.abs(start.y - end.y)); // Width & height 87 bounds = new java.awt.Rectangle( 88 Math.min(start.x ,end.x), Math.min(start.y, end.y), 89 Math.abs(start.x - end.x)+1, Math.abs(start.y - end.y)+1); 90 } 91 92 // Display the rectangle 93 public void draw(Graphics2D g2D) { 94 g2D.setPaint(color); 95 g2D.translate(position.x, position.y); // Move context origin 96 g2D.draw(rectangle); // Draw the rectangle 97 g2D.translate(-position.x, -position.y); // Move context origin back 98 } 99 100 // Method to redefine the rectangle 101 public void modify(Point start, Point last) { 102 bounds.x = position.x = Math.min(start.x, last.x); 103 bounds.y = position.y = Math.min(start.y, last.y); 104 rectangle.width = Math.abs(start.x - last.x); 105 rectangle.height = Math.abs(start.y - last.y); 106 bounds.width = (int)rectangle.width +1; 107 bounds.height = (int)rectangle.height + 1; 108 } 109 110 private Rectangle2D.Double rectangle; 111 private final static long serialVersionUID = 1001L; 112 } 113 114 // Nested class defining a circle 115 public static class Circle extends Element { 116 public Circle(Point center, Point circum, Color color) { 117 super(color); 118 119 // Radius is distance from center to circumference 120 double radius = center.distance(circum); 121 position = new Point(center.x - (int)radius, center.y - (int)radius); 122 circle = new Ellipse2D.Double(origin.x, origin.y, 2.*radius, 2.*radius); 123 bounds = new java.awt.Rectangle(position.x, position.y, 124 1 + (int)circle.width, 1+(int)circle.height); 125 } 126 127 // Display the circle 128 public void draw(Graphics2D g2D) { 129 g2D.setPaint(color); 130 g2D.translate(position.x, position.y); // Move context origin 131 g2D.draw(circle); // Draw the circle 132 g2D.translate(-position.x, -position.y); // Move context origin back 133 } 134 135 // Recreate this circle 136 public void modify(Point center, Point circum) { 137 double radius = center.distance(circum); 138 circle.width = circle.height = 2*radius; 139 position.x = center.x - (int)radius; 140 position.y = center.y - (int)radius; 141 bounds = new java.awt.Rectangle(position.x, position.y, 142 1 + (int)circle.width, 1+(int)circle.height); 143 } 144 145 private Ellipse2D.Double circle; 146 private final static long serialVersionUID = 1001L; 147 } 148 149 // Nested class defining a curve 150 public static class Curve extends Element { 151 public Curve(Point start, Point next, Color color) { 152 super(start, color); 153 curve = new GeneralPath(); 154 curve.moveTo(origin.x, origin.y); // Set current position as origin 155 curve.lineTo(next.x - position.x, next.y - position.y); // Add segment 156 bounds = new java.awt.Rectangle( 157 Math.min(start.x, next.x), Math.min(start.y, next.y), 158 Math.abs(next.x - start.x)+1, Math.abs(next.y - start.y)+1); 159 } 160 161 // Add another segment 162 public void modify(Point start, Point next) { 163 curve.lineTo(next.x - position.x, next.y - position.y); // Add segment 164 bounds.add(new java.awt.Rectangle(next.x,next.y, 1, 1)); // Extend bounds 165 } 166 167 168 // Display the curve 169 public void draw(Graphics2D g2D) { 170 g2D.setPaint(color); 171 g2D.translate(position.x, position.y); // Move context origin 172 g2D.draw(curve); // Draw the curve 173 g2D.translate(-position.x, -position.y); // Move context origin back 174 } 175 176 private GeneralPath curve; 177 private final static long serialVersionUID = 1001L; 178 } 179 180 // Nested class defining a Text element 181 public static class Text extends Element { 182 public Text(String text, Point start, Color color, FontMetrics fm) { 183 super(start, color); 184 this.text = text; 185 this.font = fm.getFont(); 186 maxAscent = fm.getMaxAscent(); 187 bounds = new java.awt.Rectangle(position.x, position.y, 188 fm.stringWidth(text) + 4, maxAscent+ fm.getMaxDescent() + 4); 189 System.out.println(bounds); 190 } 191 192 public void draw(Graphics2D g2D) { 193 g2D.setPaint(color); 194 Font oldFont = g2D.getFont(); // Save the old font 195 g2D.setFont(font); // Set the new font 196 // Reference point for drawString() is the baseline of the 1st character 197 g2D.drawString(text, position.x + 2, position.y + maxAscent + 2); 198 g2D.setFont(oldFont); // Restore the old font 199 } 200 201 public void modify(Point start, Point last) { 202 // No code is required here, but you must supply a definition 203 } 204 205 private Font font; // The font to be used 206 private int maxAscent; // Maximum ascent 207 private String text; // Text to be displayed 208 private final static long serialVersionUID = 1001L; 209 } 210 211 // Abstract Element class methods 212 public abstract void draw(Graphics2D g2D); 213 public abstract void modify(Point start, Point last); 214 215 // Element class fields 216 protected Point position; // Position of a shape 217 protected Color color; // Color of a shape 218 protected java.awt.Rectangle bounds; // Bounding rectangle 219 protected static final Point origin = new Point(); // Origin for elements 220 private final static long serialVersionUID = 1001L; 221 }
3、修改视图类,通过mouseClicked()事件处理创建文本事件:
1 import javax.swing.*; 2 import java.util.*; 3 import java.awt.*; 4 import java.awt.event.MouseEvent; 5 import javax.swing.event.MouseInputAdapter; 6 import static Constants.SketcherConstants.*; 7 8 @SuppressWarnings("serial") 9 public class SketcherView extends JComponent implements Observer { 10 public SketcherView(Sketcher theApp) { 11 this.theApp = theApp; 12 MouseHandler handler = new MouseHandler(); // create the mouse listener 13 addMouseListener(handler); // Listen for button events 14 addMouseMotionListener(handler); // Listen for motion events 15 } 16 17 // Method called by Observable object when it changes 18 public void update(Observable o, Object rectangle) { 19 if(rectangle != null) { 20 repaint((java.awt.Rectangle)rectangle); 21 } else { 22 repaint(); 23 } 24 } 25 26 // Method to draw on the view 27 @Override 28 public void paint(Graphics g) { 29 Graphics2D g2D = (Graphics2D)g; // Get a 2D device context 30 for(Element element: theApp.getModel()) { // For each element in the model 31 element.draw(g2D); // ...draw the element 32 } 33 } 34 35 class MouseHandler extends MouseInputAdapter { 36 @Override 37 public void mousePressed(MouseEvent e) { 38 start = e.getPoint(); // Save the cursor position in start 39 buttonState = e.getButton(); // Record which button was pressed 40 if(theApp.getWindow().getElementType() == TEXT) return; 41 42 if(buttonState == MouseEvent.BUTTON1) { 43 g2D = (Graphics2D)getGraphics(); // Get graphics context 44 g2D.setXORMode(getBackground()); // Set XOR mode 45 } 46 } 47 48 @Override 49 public void mouseDragged(MouseEvent e) { 50 last = e.getPoint(); // Save cursor position 51 if(theApp.getWindow().getElementType() == TEXT) return; 52 53 if(buttonState == MouseEvent.BUTTON1) { 54 if(tempElement == null) { // Is there an element? 55 tempElement = Element.createElement( // No, so create one 56 theApp.getWindow().getElementType(), 57 theApp.getWindow().getElementColor(), 58 start, last); 59 } else { 60 tempElement.draw(g2D); // Yes draw to erase it 61 tempElement.modify(start, last); // Now modify it 62 } 63 tempElement.draw(g2D); // and draw it 64 } 65 } 66 67 @Override 68 public void mouseReleased(MouseEvent e) { 69 if(theApp.getWindow().getElementType() == TEXT) { 70 if(last != null) { 71 start = last = null; 72 } 73 return; 74 } 75 76 if(e.getButton() == MouseEvent.BUTTON1) { 77 buttonState = MouseEvent.NOBUTTON; // Reset the button state 78 79 if(tempElement != null) { // If there is an element... 80 theApp.getModel().add(tempElement); // ...add it to the model... 81 tempElement = null; // ...and reset the field 82 } 83 if(g2D != null) { // If there抯 a graphics context 84 g2D.dispose(); // ...release the resource... 85 g2D = null; // ...and reset field to null 86 } 87 start = last = null; // Remove any points 88 } 89 } 90 91 @Override 92 public void mouseClicked(MouseEvent e) { 93 // Only if it's TEXT and button 1 was clicked 94 if(theApp.getWindow().getElementType() == TEXT && 95 buttonState == MouseEvent.BUTTON1) { 96 String text = JOptionPane.showInputDialog( 97 theApp.getWindow(),"Enter Input:", 98 "Create Text Element", JOptionPane.PLAIN_MESSAGE); 99 100 if(text != null && !text.isEmpty()) { // Only if text was entered 101 g2D = (Graphics2D)getGraphics(); 102 tempElement = new Element.Text(text, 103 start, 104 theApp.getWindow().getElementColor(), 105 g2D.getFontMetrics(theApp.getWindow().getFont())); 106 g2D.dispose(); 107 g2D = null; 108 if(tempElement != null) { 109 theApp.getModel().add(tempElement); 110 } 111 } 112 tempElement = null; // Reset for next element creation 113 start = null; // Reset for next element 114 } 115 } 116 117 @Override 118 public void mouseEntered(MouseEvent e) { 119 setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); 120 } 121 122 @Override 123 public void mouseExited(MouseEvent e) { 124 setCursor(Cursor.getDefaultCursor()); 125 } 126 127 private Point start; // Stores cursor position on press 128 private Point last; // Stores cursor position on drag 129 private Element tempElement = null; // Stores a temporary element 130 private int buttonState = MouseEvent.NOBUTTON; // Records button state 131 private Graphics2D g2D = null; // Temporary graphics context 132 } 133 134 private Sketcher theApp; // The application object 135 }
遗留问题:
在定义文本类中Text类的构造函数中最后有一句System.out.println(bounds)不懂:
1 public Text(String text, Point start, Color color, FontMetrics fm) { 2 super(start, color); 3 this.text = text; 4 this.font = fm.getFont(); 5 maxAscent = fm.getMaxAscent(); 6 bounds = new java.awt.Rectangle(position.x, position.y, 7 fm.stringWidth(text) + 4, maxAscent+ fm.getMaxDescent() + 4); 8 System.out.println(bounds); 9 }
注释掉这句后好像和没注释一样效果。