Java基础之扩展GUI——高亮元素、上下文菜单、移动旋转元素、自定义颜色(Sketcher 10)

窗口应用程序。

本例在上一版的基础上实现了高亮元素、移动元素、上下文菜单、旋转元素、设置自定义颜色。

1、自定义常量包:

 1 // Defines application wide constants
 2 package Constants;
 3 import java.awt.*;
 4 import javax.swing.*;
 5 import java.awt.image.BufferedImage;
 6 
 7 public class SketcherConstants {
 8   // Path for images
 9   public final static String imagePath = "E:/JavaProject/BeginningJava/Images/";
10 
11   // Toolbar icons
12   public final static Icon NEW24 = new ImageIcon(imagePath + "New24.gif");
13   public final static Icon OPEN24 = new ImageIcon(imagePath + "Open24.gif");
14   public final static Icon SAVE24 = new ImageIcon(imagePath + "Save24.gif");
15   public final static Icon SAVEAS24 = new ImageIcon(imagePath + "SaveAs24.gif");
16   public final static Icon PRINT24 = new ImageIcon(imagePath + "Print24.gif");
17 
18   public final static Icon LINE24 = new ImageIcon(imagePath + "Line24.gif");
19   public final static Icon RECTANGLE24 = new ImageIcon(imagePath + "Rectangle24.gif");
20   public final static Icon CIRCLE24 = new ImageIcon(imagePath + "Circle24.gif");
21   public final static Icon CURVE24 = new ImageIcon(imagePath + "Curve24.gif");
22   public final static Icon TEXT24 = new ImageIcon(imagePath + "Text24.gif");
23 
24   public final static Icon RED24 = new ImageIcon(imagePath + "Red24.gif");
25   public final static Icon GREEN24 = new ImageIcon(imagePath + "Green24.gif");
26   public final static Icon BLUE24 = new ImageIcon(imagePath + "Blue24.gif");
27   public final static Icon YELLOW24 = new ImageIcon(imagePath + "Yellow24.gif");
28   public final static ImageIcon CUSTOM24 = new ImageIcon(new BufferedImage(24, 24, BufferedImage.TYPE_INT_ARGB));
29 
30   // Menu item icons
31   public final static Icon NEW16 = new ImageIcon(imagePath + "new16.gif");
32   public final static Icon OPEN16 = new ImageIcon(imagePath + "Open16.gif");
33   public final static Icon SAVE16 = new ImageIcon(imagePath + "Save16.gif");
34   public final static Icon SAVEAS16 = new ImageIcon(imagePath + "SaveAs16.gif");
35   public final static Icon PRINT16 = new ImageIcon(imagePath + "print16.gif");
36 
37   public final static Icon LINE16 = new ImageIcon(imagePath + "Line16.gif");
38   public final static Icon RECTANGLE16 = new ImageIcon(imagePath + "Rectangle16.gif");
39   public final static Icon CIRCLE16 = new ImageIcon(imagePath + "Circle16.gif");
40   public final static Icon CURVE16 = new ImageIcon(imagePath + "Curve16.gif");
41   public final static Icon TEXT16 = new ImageIcon(imagePath + "Text16.gif");
42 
43   public final static Icon RED16 = new ImageIcon(imagePath + "Red16.gif");
44   public final static Icon GREEN16 = new ImageIcon(imagePath + "Green16.gif");
45   public final static Icon BLUE16 = new ImageIcon(imagePath + "Blue16.gif");
46   public final static Icon YELLOW16 = new ImageIcon(imagePath + "Yellow16.gif");
47   public final static ImageIcon CUSTOM16 = new ImageIcon(new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB));
48 
49   // Element type definitions
50   public final static int LINE      = 101;
51   public final static int RECTANGLE = 102;
52   public final static int CIRCLE    = 103;
53   public final static int CURVE     = 104;
54   public final static int TEXT      = 105;
55 
56   // Initial conditions
57   public final static int DEFAULT_ELEMENT_TYPE = LINE;
58   public final static Color DEFAULT_ELEMENT_COLOR = Color.BLUE;
59   public final static Color HIGHLIGHT_COLOR = Color.MAGENTA;
60   public final static Font DEFAULT_FONT = new Font("Serif", Font.BOLD, 12);
61 
62   // Font point size range specification
63   public final static int POINT_SIZE_MIN = 8;                           // Minimum font point size
64   public final static int POINT_SIZE_MAX = 24;                          // Maximum font point size
65   public final static int POINT_SIZE_STEP = 2;                          // Point size step
66 
67   // Operating modes
68   public final static String NORMAL = "Normal";
69   public final static String MOVE   = "Move";
70   public final static String ROTATE = "Rotate";
71 }
View Code

2、窗口框架:

  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 import java.awt.image.BufferedImage;
  7 import java.awt.font.TextLayout;
  8 import java.awt.geom.Rectangle2D;
  9 
 10 import static java.awt.event.InputEvent.*;
 11 import static java.awt.Color.*;
 12 import static Constants.SketcherConstants.*;
 13 import static javax.swing.Action.*;
 14 
 15 @SuppressWarnings("serial")
 16 public class SketcherFrame extends JFrame implements ActionListener {
 17   // Constructor
 18   public SketcherFrame(String title, Sketcher theApp) {
 19     setTitle(title);                                                    // Set the window title
 20     this.theApp = theApp;                                               // Save app. object reference
 21     setJMenuBar(menuBar);                                               // Add the menu bar to the window
 22     setDefaultCloseOperation(EXIT_ON_CLOSE);                            // Default is exit the application
 23 
 24     setCustomIconColor(CUSTOM16,customColor);                           // Setup small custom color icon
 25     setCustomIconColor(CUSTOM24,customColor);                           // Setup large custom color icon
 26     createFileMenu();                                                   // Create the File menu
 27     createElementMenu();                                                // Create the element menu
 28     createColorMenu();                                                  // Create the element menu
 29     optionsMenu = new JMenu("Options");                                 // Create options menu
 30     optionsMenu.setMnemonic('O');                                       // Create shortcut
 31     menuBar.add(optionsMenu);                                           // Add options to menu bar
 32 
 33     createPopupMenu();                                                  // Create popup
 34 
 35     // Add the font choice item to the options menu
 36     fontItem = new JMenuItem("Choose font...");
 37     fontItem.addActionListener(this);
 38     optionsMenu.add(fontItem);
 39 
 40     fontDlg = new FontDialog(this);                                     // Create the font dialog
 41 
 42     createToolbar();
 43     toolBar.setRollover(true);
 44 
 45     JMenu helpMenu = new JMenu("Help");                                 // Create Help menu
 46     helpMenu.setMnemonic('H');                                          // Create Help shortcut
 47 
 48     // Add the About item to the Help menu
 49     aboutItem = new JMenuItem("About");                                 // Create About menu item
 50     aboutItem.addActionListener(this);                                  // Listener is the frame
 51     helpMenu.add(aboutItem);                                            // Add item to menu
 52     menuBar.add(helpMenu);                                              // Add Help menu to menu bar
 53 
 54     getContentPane().add(toolBar, BorderLayout.NORTH);                  // Add the toolbar
 55     getContentPane().add(statusBar, BorderLayout.SOUTH);                // Add the statusbar
 56   }
 57 
 58   // Create File menu item actions
 59   private void createFileMenuActions() {
 60     newAction = new FileAction("New", 'N', CTRL_DOWN_MASK);
 61     openAction = new FileAction("Open", 'O', CTRL_DOWN_MASK);
 62     closeAction = new FileAction("Close");
 63     saveAction = new FileAction("Save", 'S', CTRL_DOWN_MASK);
 64     saveAsAction = new FileAction("Save As...");
 65     printAction = new FileAction("Print", 'P', CTRL_DOWN_MASK);
 66     exitAction = new FileAction("Exit", 'X', CTRL_DOWN_MASK);
 67 
 68     // Initialize the array
 69     FileAction[] actions = {openAction, closeAction, saveAction, saveAsAction, printAction, exitAction};
 70     fileActions = actions;
 71 
 72     // Add toolbar icons
 73     newAction.putValue(LARGE_ICON_KEY, NEW24);
 74     openAction.putValue(LARGE_ICON_KEY, OPEN24);
 75     saveAction.putValue(LARGE_ICON_KEY, SAVE24);
 76     saveAsAction.putValue(LARGE_ICON_KEY, SAVEAS24);
 77     printAction.putValue(LARGE_ICON_KEY, PRINT24);
 78 
 79     // Add menu item icons
 80     newAction.putValue(SMALL_ICON, NEW16);
 81     openAction.putValue(SMALL_ICON, OPEN16);
 82     saveAction.putValue(SMALL_ICON, SAVE16);
 83     saveAsAction.putValue(SMALL_ICON,SAVEAS16);
 84     printAction.putValue(SMALL_ICON, PRINT16);
 85 
 86     // Add tooltip text
 87     newAction.putValue(SHORT_DESCRIPTION, "Create a new sketch");
 88     openAction.putValue(SHORT_DESCRIPTION, "Read a sketch from a file");
 89     closeAction.putValue(SHORT_DESCRIPTION, "Close the current sketch");
 90     saveAction.putValue(SHORT_DESCRIPTION, "Save the current sketch to file");
 91     saveAsAction.putValue(SHORT_DESCRIPTION, "Save the current sketch to a new file");
 92     printAction.putValue(SHORT_DESCRIPTION, "Print the current sketch");
 93     exitAction.putValue(SHORT_DESCRIPTION, "Exit Sketcher");
 94   }
 95 
 96   // Helper method to set custom icon color
 97   private void setCustomIconColor(ImageIcon icon, Color color) {
 98     BufferedImage image = (BufferedImage)(icon.getImage());
 99     int width = image.getWidth();                                       // Image width
100     int indent =  width == 16 ? 3 : 2;                                  // Indent for filled rectangle
101     int rectSize = width - 2*indent;                                    // Filled rectangle size
102     Graphics2D g2D = image.createGraphics();
103     g2D.setPaint(color);
104     g2D.fillRect(indent,indent,rectSize,rectSize);                      // Fill centered rectangle
105     if(width == 24) {
106       TextLayout textLayout = new TextLayout("C", g2D.getFont(), g2D.getFontRenderContext());
107       Rectangle2D.Float rect = (Rectangle2D.Float)textLayout.getBounds();
108       g2D.setPaint(new Color(255-color.getRed(),255-color.getGreen(), 255-color.getBlue()));
109       g2D.drawString("C", (width-rect.width)/2, (width+rect.height)/2);
110     }
111     g2D.dispose();
112   }
113 
114 
115   // Create the File menu
116   private void createFileMenu() {
117     JMenu fileMenu = new JMenu("File");                                 // Create File menu
118     fileMenu.setMnemonic('F');                                          // Create shortcut
119     createFileMenuActions();                                            // Create Actions for File menu item
120 
121     // Construct the file drop-down menu
122     fileMenu.add(newAction);                                            // New Sketch menu item
123     fileMenu.add(openAction);                                           // Open sketch menu item
124     fileMenu.add(closeAction);                                          // Close sketch menu item
125     fileMenu.addSeparator();                                            // Add separator
126     fileMenu.add(saveAction);                                           // Save sketch to file
127     fileMenu.add(saveAsAction);                                         // Save As menu item
128     fileMenu.addSeparator();                                            // Add separator
129     fileMenu.add(printAction);                                          // Print sketch menu item
130     fileMenu.addSeparator();                                            // Add separator
131     fileMenu.add(exitAction);                                           // Print sketch menu item
132     menuBar.add(fileMenu);                                              // Add the file menu
133   }
134 
135   // Create Element  menu actions
136   private void createElementTypeActions() {
137     lineAction = new TypeAction("Line", LINE, 'L', CTRL_DOWN_MASK);
138     rectangleAction = new TypeAction("Rectangle", RECTANGLE, 'R', CTRL_DOWN_MASK);
139     circleAction =  new TypeAction("Circle", CIRCLE,'C', CTRL_DOWN_MASK);
140     curveAction = new TypeAction("Curve", CURVE,'U', CTRL_DOWN_MASK);
141     textAction = new TypeAction("Text", TEXT,'T', CTRL_DOWN_MASK);
142 
143     // Initialize the array
144     TypeAction[] actions = {lineAction, rectangleAction, circleAction, curveAction, textAction};
145     typeActions = actions;
146 
147     // Add toolbar icons
148     lineAction.putValue(LARGE_ICON_KEY, LINE24);
149     rectangleAction.putValue(LARGE_ICON_KEY, RECTANGLE24);
150     circleAction.putValue(LARGE_ICON_KEY, CIRCLE24);
151     curveAction.putValue(LARGE_ICON_KEY, CURVE24);
152     textAction.putValue(LARGE_ICON_KEY, TEXT24);
153 
154     // Add menu item icons
155     lineAction.putValue(SMALL_ICON, LINE16);
156     rectangleAction.putValue(SMALL_ICON, RECTANGLE16);
157     circleAction.putValue(SMALL_ICON, CIRCLE16);
158     curveAction.putValue(SMALL_ICON, CURVE16);
159     textAction.putValue(SMALL_ICON, TEXT16);
160 
161     // Add tooltip text
162     lineAction.putValue(SHORT_DESCRIPTION, "Draw lines");
163     rectangleAction.putValue(SHORT_DESCRIPTION, "Draw rectangles");
164     circleAction.putValue(SHORT_DESCRIPTION, "Draw circles");
165     curveAction.putValue(SHORT_DESCRIPTION, "Draw curves");
166     textAction.putValue(SHORT_DESCRIPTION, "Draw text");
167   }
168 
169   // Create the Elements menu
170   private void createElementMenu() {
171     createElementTypeActions();
172     elementMenu = new JMenu("Elements");                                // Create Elements menu
173     elementMenu.setMnemonic('E');                                       // Create shortcut
174     createRadioButtonDropDown(elementMenu, typeActions, lineAction);
175     menuBar.add(elementMenu);                                           // Add the element menu
176   }
177 
178   // Create Color menu actions
179   private void createElementColorActions() {
180     redAction = new ColorAction("Red", RED, 'R', CTRL_DOWN_MASK|ALT_DOWN_MASK);
181     yellowAction = new ColorAction("Yellow", YELLOW, 'Y', CTRL_DOWN_MASK|ALT_DOWN_MASK);
182     greenAction = new ColorAction("Green", GREEN, 'G', CTRL_DOWN_MASK|ALT_DOWN_MASK);
183     blueAction = new ColorAction("Blue", BLUE, 'B', CTRL_DOWN_MASK|ALT_DOWN_MASK);
184     customAction = new ColorAction("Custom...", BLUE, 'C', CTRL_DOWN_MASK|ALT_DOWN_MASK);
185 
186     // Initialize the array
187     ColorAction[] actions = {redAction, greenAction, blueAction, yellowAction, customAction};
188     colorActions = actions;
189 
190     // Add toolbar icons
191     redAction.putValue(LARGE_ICON_KEY, RED24);
192     greenAction.putValue(LARGE_ICON_KEY, GREEN24);
193     blueAction.putValue(LARGE_ICON_KEY, BLUE24);
194     yellowAction.putValue(LARGE_ICON_KEY, YELLOW24);
195     customAction.putValue(LARGE_ICON_KEY, CUSTOM24);
196 
197     // Add menu item icons
198     redAction.putValue(SMALL_ICON, RED16);
199     greenAction.putValue(SMALL_ICON, GREEN16);
200     blueAction.putValue(SMALL_ICON, BLUE16);
201     yellowAction.putValue(SMALL_ICON, YELLOW16);
202     customAction.putValue(SMALL_ICON, CUSTOM16);
203 
204     // Add tooltip text
205     redAction.putValue(SHORT_DESCRIPTION, "Draw in red");
206     greenAction.putValue(SHORT_DESCRIPTION, "Draw in green");
207     blueAction.putValue(SHORT_DESCRIPTION, "Draw in blue");
208     yellowAction.putValue(SHORT_DESCRIPTION, "Draw in yellow");
209     customAction.putValue(SHORT_DESCRIPTION, "Draw in custom color");
210   }
211 
212   // Create the Color menu
213   private void createColorMenu() {
214     createElementColorActions();
215     colorMenu = new JMenu("Color");                                     // Create Elements menu
216     colorMenu.setMnemonic('C');                                         // Create shortcut
217     createRadioButtonDropDown(colorMenu, colorActions, blueAction);
218     menuBar.add(colorMenu);                                             // Add the color menu
219   }
220 
221   // Menu creation helper
222   private void createRadioButtonDropDown(JMenu menu, Action[] actions, Action selected) {
223     ButtonGroup group = new ButtonGroup();
224     JRadioButtonMenuItem item = null;
225     for(Action action : actions) {
226       group.add(menu.add(item = new JRadioButtonMenuItem(action)));
227       if(action == selected) {
228         item.setSelected(true);                                         // This is default selected
229       }
230     }
231   }
232 
233   // Create pop-up menu
234   private void createPopupMenu() {
235     // Element menu items
236     popup.add(new JMenuItem(lineAction));
237     popup.add(new JMenuItem(rectangleAction));
238     popup.add(new JMenuItem(circleAction));
239     popup.add(new JMenuItem(curveAction));
240     popup.add(new JMenuItem(textAction));
241 
242     popup.addSeparator();
243 
244     // Color menu items
245     popup.add(new JMenuItem(redAction));
246     popup.add(new JMenuItem(yellowAction));
247     popup.add(new JMenuItem(greenAction));
248     popup.add(new JMenuItem(blueAction));
249     popup.add(new JMenuItem(customAction));
250   }
251 
252   // Create toolbar buttons on the toolbar
253   private void createToolbar() {
254     for(FileAction action: fileActions){
255       if(action != exitAction && action != closeAction)
256         addToolbarButton(action);                                       // Add the toolbar button
257     }
258     toolBar.addSeparator();
259 
260     // Create Color menu buttons
261     for(ColorAction action:colorActions){
262         addToolbarButton(action);                                       // Add the toolbar button
263     }
264 
265     toolBar.addSeparator();
266 
267     // Create Elements menu buttons
268     for(TypeAction action:typeActions){
269         addToolbarButton(action);                                       // Add the toolbar button
270     }
271  }
272 
273   // Create and add a toolbar button
274   private void addToolbarButton(Action action) {
275     JButton button = new JButton(action);                               // Create from Action
276     button.setBorder(BorderFactory.createCompoundBorder(                // Add button border
277            new EmptyBorder(2,5,5,2),                                    // Outside border
278            BorderFactory.createRaisedBevelBorder()));                   // Inside border
279     button.setHideActionText(true);                                     // No label on the button
280     toolBar.add(button);                                                // Add the toolbar button
281   }
282 
283   // Return the current drawing color
284   public Color getElementColor() {
285     return elementColor;
286   }
287 
288   // Return the current element type
289   public int getElementType() {
290     return elementType;
291   }
292 
293   // Return current text font
294   public Font getFont() {
295     return textFont;
296   }
297 
298   // Method to set the current font
299   public void setFont(Font font) {
300     textFont = font;
301   }
302 
303   // Retrieve the pop-up menu
304   public JPopupMenu getPopup() {
305     return popup;
306   }
307 
308   // Set radio button menu checks
309   private void setChecks(JMenu menu, Object eventSource) {
310     if(eventSource instanceof JButton){
311       JButton button = (JButton)eventSource;
312       Action action = button.getAction();
313       for(int i = 0 ; i<menu.getItemCount() ; ++i) {
314         JMenuItem item = menu.getItem(i);
315         item.setSelected(item.getAction() == action);
316       }
317     }
318   }
319 
320   // Handle About menu events
321   public void actionPerformed(ActionEvent e)  {
322     if(e.getSource() == aboutItem) {
323       // Create about dialog with the app window as parent
324       JOptionPane.showMessageDialog(this,                               // Parent
325                        "Sketcher Copyright Ivor Horton 2011",           // Message
326                        "About Sketcher",                                // Title
327                        JOptionPane.INFORMATION_MESSAGE);                // Message type
328     } else if(e.getSource() == fontItem) {                              // Set the dialog window position
329       fontDlg.setLocationRelativeTo(this);
330       fontDlg.setVisible(true);                                         // Show the dialog
331     }
332   }
333 
334   // Inner class defining Action objects for File menu items
335   class FileAction extends AbstractAction {
336     // Create action with a name
337     FileAction(String name) {
338       super(name);
339     }
340 
341     // Create action with a name and accelerator
342     FileAction(String name, char ch, int modifiers) {
343       super(name);
344       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(ch, modifiers));
345 
346       // Now find the character to underline
347       int index = name.toUpperCase().indexOf(ch);
348       if(index != -1) {
349         putValue(DISPLAYED_MNEMONIC_INDEX_KEY, index);
350       }
351     }
352 
353     // Event handler
354     public void actionPerformed(ActionEvent e) {
355       // You will add action code here eventually...
356     }
357   }
358 
359   // Inner class defining Action objects for Element type menu items
360   class TypeAction extends AbstractAction {
361     // Create action with just a name property
362     TypeAction(String name, int typeID) {
363       super(name);
364       this.typeID = typeID;
365     }
366 
367     // Create action with a name and an accelerator
368     private TypeAction(String name,int typeID, char ch, int modifiers) {
369       this(name, typeID);
370       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(ch, modifiers));
371 
372       // Now find the character to underline
373       int index = name.toUpperCase().indexOf(ch);
374       if(index != -1) {
375         putValue(DISPLAYED_MNEMONIC_INDEX_KEY, index);
376       }
377     }
378 
379     public void actionPerformed(ActionEvent e) {
380       elementType = typeID;
381       setChecks(elementMenu, e.getSource());
382       statusBar.setTypePane(typeID);
383     }
384 
385     private int typeID;
386   }
387 
388   // Handles color menu items
389   class ColorAction  extends AbstractAction {
390     // Create an action with a name and a color
391     public ColorAction(String name, Color color) {
392       super(name);
393       this.color = color;
394     }
395 
396     // Create an action with a name, a color, and an accelerator
397     public ColorAction(String name, Color color, char ch, int modifiers) {
398       this(name, color);
399       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(ch, modifiers));
400 
401       // Now find the character to underline
402       int index = name.toUpperCase().indexOf(ch);
403       if(index != -1) {
404         putValue(DISPLAYED_MNEMONIC_INDEX_KEY, index);
405       }
406     }
407 
408     public void actionPerformed(ActionEvent e) {
409       if(this == customAction) {
410         // This could be a new custom color
411         Color newColor = JColorChooser.showDialog(SketcherFrame.this, "Select Custom Color", customColor);
412         if(newColor != null) {
413           elementColor = customColor = newColor;
414 
415           // Setup small custom color icons
416           setCustomIconColor(CUSTOM16,customColor);
417           setCustomIconColor(CUSTOM24,customColor);
418           toolBar.repaint();                                            // Repaint the toolbar
419         }
420       } else {
421           // This is just a standard color change
422           elementColor = color;
423       }
424       statusBar.setColorPane(elementColor);                             // Update the status bar
425       setChecks(colorMenu, e.getSource());                              // Set Color menu checks
426     }
427 
428     private Color color;
429   }
430 
431   // File actions
432   private FileAction newAction, openAction, closeAction, saveAction, saveAsAction, printAction, exitAction;
433   private FileAction[] fileActions;                                     // File actions as an array
434 
435   // Element type actions
436   private TypeAction lineAction, rectangleAction, circleAction, curveAction, textAction;
437   private TypeAction[] typeActions;                                     // Type actions as an array
438 
439 // Element color actions
440   private ColorAction redAction, yellowAction,greenAction, blueAction, customAction;
441   private ColorAction[] colorActions;                                   // Color actions as an array
442 
443   private JMenuBar menuBar = new JMenuBar();                            // Window menu bar
444   private JMenu elementMenu;                                            // Elements menu
445   private JMenu colorMenu;                                              // Color menu
446   private JMenu optionsMenu;                                            // Options menu
447 
448   private StatusBar statusBar = new StatusBar();                        // Window status bar
449   private FontDialog fontDlg;                                           // The font dialog
450 
451   private JMenuItem aboutItem;                                          // About menu item
452   private JMenuItem fontItem;                                           // Font chooser menu item
453 
454   private JPopupMenu popup = new JPopupMenu("General");                 // Window pop-up
455   private Color elementColor = DEFAULT_ELEMENT_COLOR;                   // Current element color
456   private Color customColor = DEFAULT_ELEMENT_COLOR;                    // Current custom color
457   private int elementType = DEFAULT_ELEMENT_TYPE;                       // Current element type
458   private Font textFont = DEFAULT_FONT;                                 // Default font for text elements
459   private JToolBar toolBar = new JToolBar();                            // Window toolbar
460   private Sketcher theApp;                                              // The application object
461 }
View Code

3、元素类:

  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     AffineTransform at = AffineTransform.getTranslateInstance(position.x, position.y);
 30     at.rotate(angle);
 31     at.translate(-position.x, -position.y);
 32     return  at.createTransformedShape(bounds).getBounds();
 33   }
 34 
 35   // Set or reset highlight color
 36   public void setHighlighted(boolean highlighted) {
 37     this.highlighted = highlighted;
 38   }
 39 
 40   // Create a new element
 41   public static Element createElement(int type, Color color, Point start, Point end) {
 42     switch(type) {
 43       case LINE:
 44         return new Element.Line(start, end, color);
 45       case RECTANGLE:
 46          return new Rectangle(start, end, color);
 47       case CIRCLE:
 48         return new Circle(start, end, color);
 49       case CURVE:
 50         return new Curve(start, end, color);
 51       default:
 52        assert false;                                                    // We should never get to here
 53     }
 54     return null;
 55   }
 56 
 57   // Draw a geometric element of type Shape
 58   protected void draw(Graphics2D g2D, Shape element) {
 59     g2D.setPaint(highlighted ? Color.MAGENTA : color);                  // Set the element color
 60     AffineTransform old = g2D.getTransform();                           // Save copy of current transform
 61     g2D.translate((double)position.x, (double)position.y);              // Add a translation to current transform
 62     g2D.rotate(angle);                                                  // Rotate about position
 63      g2D.draw(element);                                                 // Draw the element
 64     g2D.setTransform(old);                                              // Restore original transform
 65   }
 66 
 67   // Move an element
 68   public void move(int deltaX, int deltaY) {
 69     position.translate(deltaX, deltaY);
 70     bounds.translate(deltaX, deltaY);
 71   }
 72 
 73   // Rotate an element
 74   public void setRotation(double angle) {
 75     this.angle = angle;
 76   }
 77 
 78   // Get the rotation angle
 79   public double getRotation() {
 80     return angle;
 81   }
 82 
 83   // Nested class defining a line
 84   public static class Line extends Element {
 85     public Line(Point start, Point end, Color color) {
 86       super(start, color);
 87       line = new Line2D.Double(origin.x, origin.y, end.x - position.x, end.y - position.y);
 88       bounds = new java.awt.Rectangle(
 89                      Math.min(start.x ,end.x),    Math.min(start.y, end.y),
 90                      Math.abs(start.x - end.x)+1, Math.abs(start.y - end.y)+1);
 91     }
 92 
 93     // Change the end point for the line
 94     public void modify(Point start, Point last) {
 95       line.x2 = last.x - position.x;
 96       line.y2 = last.y - position.y;
 97       bounds = new java.awt.Rectangle(
 98                    Math.min(start.x ,last.x),    Math.min(start.y, last.y),
 99                    Math.abs(start.x - last.x)+1, Math.abs(start.y - last.y)+1);
100     }
101 
102     // Display the line
103     public  void draw(Graphics2D g2D) {
104       draw(g2D, line);                                                  // Draw the line
105     }
106     private Line2D.Double line;
107     private final static long serialVersionUID = 1001L;
108   }
109 
110   // Nested class defining a rectangle
111   public static class Rectangle extends Element {
112     public Rectangle(Point start, Point end, Color color) {
113       super(new Point(Math.min(start.x, end.x), Math.min(start.y, end.y)), color);
114       rectangle = new Rectangle2D.Double(
115         origin.x, origin.y,                                             // Top-left corner
116         Math.abs(start.x - end.x), Math.abs(start.y - end.y));          // Width & height
117       bounds = new java.awt.Rectangle(
118                     Math.min(start.x ,end.x),    Math.min(start.y, end.y),
119                     Math.abs(start.x - end.x)+1, Math.abs(start.y - end.y)+1);
120     }
121 
122     // Display the rectangle
123     public  void draw(Graphics2D g2D) {
124       draw(g2D, rectangle);                                             // Draw the rectangle
125     }
126 
127     // Method to redefine the rectangle
128     public void modify(Point start, Point last) {
129       bounds.x = position.x = Math.min(start.x, last.x);
130       bounds.y = position.y = Math.min(start.y, last.y);
131       rectangle.width = Math.abs(start.x - last.x);
132       rectangle.height = Math.abs(start.y - last.y);
133       bounds.width = (int)rectangle.width + 1;
134       bounds.height = (int)rectangle.height + 1;
135     }
136 
137     private Rectangle2D.Double rectangle;
138     private final static long serialVersionUID = 1001L;
139   }
140 
141   // Nested class defining a circle
142   public static class Circle extends Element {
143     public Circle(Point center, Point circum, Color color) {
144       super(color);
145 
146       // Radius is distance from center to circumference
147       double radius = center.distance(circum);
148       position = new Point(center.x - (int)radius, center.y - (int)radius);
149       circle = new Ellipse2D.Double(origin.x, origin.y, 2.*radius, 2.*radius);
150       bounds = new java.awt.Rectangle(position.x, position.y,
151                               1 + (int)circle.width, 1 + (int)circle.height);
152     }
153 
154     // Display the circle
155     public  void draw(Graphics2D g2D) {
156       draw(g2D, circle);                                                // Draw the circle
157     }
158 
159     // Recreate this circle
160     public void modify(Point center, Point circum) {
161       double radius = center.distance(circum);
162       circle.width = circle.height = 2*radius;
163       position.x = center.x - (int)radius;
164       position.y = center.y - (int)radius;
165       bounds = new java.awt.Rectangle(position.x, position.y,
166                               1 + (int)circle.width, 1 + (int)circle.height);
167     }
168 
169     private Ellipse2D.Double circle;
170     private final static long serialVersionUID = 1001L;
171   }
172 
173   // Nested class defining a curve
174   public static class Curve extends Element {
175     public Curve(Point start, Point next, Color color) {
176       super(start, color);
177       curve = new GeneralPath();
178       curve.moveTo(origin.x, origin.y);                                 // Set current position as origin
179       curve.lineTo(next.x - position.x, next.y - position.y);           // Add segment
180       bounds = new java.awt.Rectangle(
181                    Math.min(start.x, next.x),    Math.min(start.y, next.y),
182                    Math.abs(next.x - start.x)+1, Math.abs(next.y - start.y)+1);
183     }
184 
185     // Add another segment
186     public void modify(Point start, Point next) {
187       curve.lineTo(next.x - position.x, next.y - position.y);           // Add segment
188       bounds.add(new java.awt.Rectangle(next.x,next.y, 1, 1));          // Extend bounds
189     }
190 
191 
192     // Display the curve
193     public  void draw(Graphics2D g2D) {
194       draw(g2D, curve);                                                 // Draw the curve
195     }
196 
197     private GeneralPath curve;
198     private final static long serialVersionUID = 1001L;
199   }
200 
201   // Nested class defining a Text element
202   public static class Text extends Element  {
203     public Text(String text, Point start, Color color, FontMetrics fm) {
204       super(start, color);
205       this.text = text;
206       this.font = fm.getFont();
207         maxAscent = fm.getMaxAscent();
208         bounds = new java.awt.Rectangle(position.x, position.y,
209                  fm.stringWidth(text) + 4, maxAscent+ fm.getMaxDescent() + 4);
210     }
211 
212     public void draw(Graphics2D g2D)  {
213       g2D.setPaint(highlighted ? HIGHLIGHT_COLOR : color);
214       Font oldFont = g2D.getFont();                                     // Save the old font
215       g2D.setFont(font);                                                // Set the new font
216 
217       AffineTransform old = g2D.getTransform();                         // Save the current transform
218       g2D.translate((double)position.x, (double)position.y);            // Add translation transform to current
219       g2D.rotate(angle);                                                // Rotate about position
220       // Reference point for drawString() is the baseline of the 1st character
221       g2D.drawString(text, origin.x + 2, maxAscent + 2);
222       g2D.setTransform(old);                                            // Restore original transform
223       g2D.setFont(oldFont);                                             // Restore the old font
224     }
225 
226     public void modify(Point start, Point last) {
227       // No code is required here, but you must supply a definition
228     }
229 
230     private Font font;                                                  // The font to be used
231     private int maxAscent;                                              // Maximum ascent
232     private String text;                                                // Text to be displayed
233     private final static long serialVersionUID = 1001L;
234   }
235 
236   // Abstract Element class methods
237   public abstract void draw(Graphics2D g2D);
238   public abstract void modify(Point start, Point last);
239 
240   // Element class fields
241   protected Point position;                                             // Position of a shape
242   protected Color color;                                                // Color of a shape
243   protected java.awt.Rectangle bounds;                                  // Bounding rectangle
244   protected static final Point origin = new Point();                    // Origin for elements
245   protected boolean highlighted = false;                                // Highlight flag
246   protected double angle = 0.0;                                         // Element rotation
247   private final static long serialVersionUID = 1001L;
248 }
View Code

4、模型类:

 1 import java.io.Serializable;
 2 import java.util.*;
 3 
 4 public class SketcherModel extends Observable implements Serializable, Iterable<Element> {
 5 
 6   //Remove an element from the sketch
 7   public boolean remove(Element element) {
 8     boolean removed = elements.remove(element);
 9     if(removed) {
10       setChanged();
11       notifyObservers(element.getBounds());
12     }
13     return removed;
14   }
15 
16   //Add an element to the sketch
17   public void add(Element element) {
18     elements.add(element);
19     setChanged();
20     notifyObservers(element.getBounds());
21   }
22 
23   // Get iterator for sketch elements
24   public Iterator<Element> iterator() {
25     return elements.iterator();
26   }
27 
28 
29   protected LinkedList<Element> elements = new LinkedList<>();
30   private final static long serialVersionUID = 1001L;
31 }
View Code

5、字体对话框类:

  1 // Class to define a dialog to choose a font
  2 import java.awt.*;
  3 import javax.swing.*;
  4 import java.awt.event.*;
  5 import javax.swing.event.*;
  6 import static Constants.SketcherConstants.*;
  7 
  8 @SuppressWarnings("serial")
  9 class FontDialog extends JDialog
 10                  implements ActionListener,                             // For buttons etc.
 11                             ListSelectionListener,                      // For list box
 12                             ChangeListener {                            // For the spinner
 13   // Constructor
 14   public FontDialog(SketcherFrame window) {
 15     // Call the base constructor to create a modal dialog
 16     super(window, "Font Selection", true);
 17     font = window.getFont();                                            // Get the current font
 18 
 19   // Create the dialog button panel
 20   JPanel buttonPane = new JPanel();                                     // Create a panel to hold buttons
 21 
 22   // Create and add the buttons to the buttonPane
 23   buttonPane.add(ok = createButton("OK"));                              // Add the OK button
 24   buttonPane.add(cancel = createButton("Cancel"));                      // Add the Cancel button
 25   getContentPane().add(buttonPane, BorderLayout.SOUTH);                 // Add pane
 26 
 27     // Code to create the data input panel
 28     JPanel dataPane = new JPanel();                                     // Create the data entry panel
 29     dataPane.setBorder(BorderFactory.createCompoundBorder(              // Pane border
 30                        BorderFactory.createLineBorder(Color.BLACK),
 31                        BorderFactory.createEmptyBorder(5, 5, 5, 5)));
 32     GridBagLayout gbLayout = new GridBagLayout();                       // Create the layout
 33     dataPane.setLayout(gbLayout);                                       // Set the pane layout
 34     GridBagConstraints constraints = new GridBagConstraints();
 35 
 36     // Create the font choice and add it to the input panel
 37     JLabel label = new JLabel("Choose a Font");
 38     constraints.fill = GridBagConstraints.HORIZONTAL;
 39     constraints.gridwidth = GridBagConstraints.REMAINDER;
 40     gbLayout.setConstraints(label, constraints);
 41     dataPane.add(label);
 42 
 43     // Code to set up font list choice component
 44     GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
 45     String[] fontNames = e.getAvailableFontFamilyNames();               // Get font names
 46 
 47     fontList = new JList<>(fontNames);                                  // Create list of font names
 48     fontList.setValueIsAdjusting(true);                                 // single event selection
 49     fontList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 50     fontList.setSelectedValue(font.getFontName(),true);
 51     fontList.addListSelectionListener(this);
 52     fontList.setToolTipText("Choose a font");
 53     JScrollPane chooseFont = new JScrollPane(fontList);                 // Scrollable list
 54     chooseFont.setMinimumSize(new Dimension(400,100));
 55     chooseFont.setWheelScrollingEnabled(true);                          // Enable mouse wheel scroll
 56 
 57     // Panel to display font sample
 58     JPanel display = new JPanel(true);
 59     fontDisplay = new JLabel("Sample Size: x X y Y z Z");
 60     fontDisplay.setFont(font);
 61     fontDisplay.setPreferredSize(new Dimension(350,100));
 62     display.add(fontDisplay);
 63 
 64     //Create a split pane with font choice at the top and font display at the bottom
 65     JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
 66                                true,
 67                                chooseFont,
 68                                display);
 69     gbLayout.setConstraints(splitPane, constraints);                    // Split pane constraints
 70     dataPane.add(splitPane);                                            // Add to the data pane
 71 
 72     // Set up the size choice using a spinner
 73     JPanel sizePane = new JPanel(true);                                 // Pane for size choices
 74     label = new JLabel("Choose point size: ");                          // Prompt for point size
 75     sizePane.add(label);                                                // Add the prompt
 76 
 77     chooseSize = new JSpinner(new SpinnerNumberModel(font.getSize(),
 78                                   POINT_SIZE_MIN, POINT_SIZE_MAX, POINT_SIZE_STEP));
 79     chooseSize.setValue(font.getSize());                                // Set current font size
 80     chooseSize.addChangeListener(this);
 81     sizePane.add(chooseSize);
 82 
 83      // Add spinner to pane
 84     gbLayout.setConstraints(sizePane, constraints);                     // Set pane constraints
 85     dataPane.add(sizePane);                                             // Add the pane
 86 
 87     // Set up style options using radio buttons
 88     bold = new JRadioButton("Bold", (font.getStyle() & Font.BOLD) > 0);
 89     italic = new JRadioButton("Italic", (font.getStyle() & Font.ITALIC) > 0);
 90     bold.addItemListener(new StyleListener(Font.BOLD));                 // Add button listeners
 91     italic.addItemListener(new StyleListener(Font.ITALIC));
 92     JPanel stylePane = new JPanel(true);                                // Create style pane
 93     stylePane.add(bold);                                                // Add buttons
 94     stylePane.add(italic);                                              // to style pane...
 95     gbLayout.setConstraints(stylePane, constraints);                    // Set pane constraints
 96     dataPane.add(stylePane);                                            // Add the pane
 97 
 98     getContentPane().add(dataPane, BorderLayout.CENTER);
 99     pack();
100     setVisible(false);
101   }
102 
103   // Create a dialog button
104   JButton createButton(String label) {
105     JButton button = new JButton(label);                                // Create the button
106     button.setPreferredSize(new Dimension(80,20));                      // Set the size
107     button.addActionListener(this);                                     // Listener is the dialog
108     return button;                                                      // Return the button
109   }
110 
111   // Handler for button events
112   public void actionPerformed(ActionEvent e) {
113     if(e.getSource()== ok)  {                                           // If it's the OK button
114       ((SketcherFrame)getOwner()).setFont(font);                        // ...set selected font
115     } else {
116       font = ((SketcherFrame)getOwner()).getFont();                     // Restore the current font
117       fontDisplay.setFont(font);
118       chooseSize.setValue(font.getSize());                              // Restore the point size
119       fontList.setSelectedValue(font.getName(),true);
120       int style = font.getStyle();
121       bold.setSelected((style & Font.BOLD) > 0);                        // Restore the
122       italic.setSelected((style & Font.ITALIC) > 0);                    // style options
123     }
124     // Now hide the dialog - for ok or cancel
125     setVisible(false);
126   }
127 
128   // List selection listener method
129   public void valueChanged(ListSelectionEvent e) {
130     if(!e.getValueIsAdjusting()) {
131       font = new Font(fontList.getSelectedValue(), font.getStyle(), font.getSize());
132       fontDisplay.setFont(font);
133       fontDisplay.repaint();
134     }
135   }
136 
137   // Handle spinner state change events
138   public void stateChanged(ChangeEvent e) {
139     int fontSize = ((Number)(((JSpinner)e.getSource()).getValue())).intValue();
140     font = font.deriveFont((float)fontSize);
141     fontDisplay.setFont(font);
142     fontDisplay.repaint();
143   }
144 
145   // Iner class defining listeners for radio buttons
146   class StyleListener implements ItemListener {
147     public StyleListener(int style) {
148       this.style = style;
149     }
150 
151     // Event handler for font style changes
152     public void itemStateChanged(ItemEvent e) {
153       int fontStyle = font.getStyle();
154       if(e.getStateChange()==ItemEvent.SELECTED) {                      // If style was selected
155         fontStyle |= style;                                             // turn it on in the font style
156       } else {
157         fontStyle &= ~style;                                            // otherwise turn it off
158       }
159       font = font.deriveFont(fontStyle);                                // Get a new font
160       fontDisplay.setFont(font);                                        // Change the label font
161       fontDisplay.repaint();                                            // repaint
162     }
163      private int style;                                                 // Style for this listener
164   }
165 
166   private JList<String> fontList;                                       // Font list
167   private JButton ok;                                                   // OK button
168   private JButton cancel;                                               // Cancel button
169   private JRadioButton bold;                                            // Bold style button
170   private JRadioButton italic;                                          // Italic style button
171   private Font font;                                                    // Currently selected font
172   private JSpinner chooseSize;                                          // Font size options
173   private JLabel fontDisplay;                                           // Font sample
174 }
View Code

6、状态栏类:

  1 // Class defining a status bar
  2 import javax.swing.*;
  3 import java.awt.*;
  4 import javax.swing.border.BevelBorder;
  5 import static Constants.SketcherConstants.*;
  6 
  7 @SuppressWarnings("serial")
  8 class StatusBar extends JPanel {
  9   // Constructor
 10   public StatusBar() {
 11     setLayout(new FlowLayout(FlowLayout.LEFT, 10, 3));
 12     setBackground(Color.LIGHT_GRAY);
 13     setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
 14     setColorPane(DEFAULT_ELEMENT_COLOR);
 15     setTypePane(DEFAULT_ELEMENT_TYPE);
 16     add(colorPane);                                                     // Add color pane to status bar
 17     add(typePane);                                                      // Add type pane to status bar
 18   }
 19 
 20   // Set color pane contents
 21   public void setColorPane(Color color) {
 22     String text = null;                                                 // Text for the color pane
 23     Icon icon = null;                                                   // Icon to be displayed
 24     if(color.equals(Color.RED)) {
 25       text = "RED";
 26       icon = RED16;
 27     } else if(color.equals(Color.YELLOW)) {
 28       text = "YELLOW";
 29       icon = YELLOW16;
 30     } else if(color.equals(Color.GREEN)) {
 31       text = "GREEN";
 32       icon = GREEN16;
 33     } else if(color.equals(Color.BLUE)) {
 34       text = "BLUE";
 35       icon = BLUE16;
 36     } else {
 37       text = "CUSTOM";
 38       icon = CUSTOM16;
 39     }
 40     colorPane.setIcon(icon);
 41     colorPane.setText(text);                                            // Set the pane text
 42   }
 43 
 44   // Set type pane label
 45   public void setTypePane(int elementType) {
 46     String text = null;                                                 // Text for the type pane
 47     switch(elementType) {
 48       case LINE:
 49         text = "LINE";
 50         break;
 51       case RECTANGLE:
 52         text = "RECTANGLE";
 53         break;
 54       case CIRCLE:
 55         text = "CIRCLE";
 56         break;
 57       case CURVE:
 58         text = "CURVE";
 59         break;
 60         case TEXT:
 61         text = "TEXT";
 62         break;
 63       default:
 64         assert false;
 65     }
 66     typePane.setText(text);                                             // Set the pane text
 67   }
 68 
 69   // Panes in the status bar
 70   private StatusPane colorPane = new StatusPane("BLUE", BLUE16);;
 71   private StatusPane typePane = new StatusPane("LINE");
 72 
 73   // Class defining a status bar pane
 74   class StatusPane extends JLabel {
 75     // Constructor - text only
 76     public StatusPane(String text) {
 77       super(text, LEFT);
 78       setupPane();
 79     }
 80 
 81     // Constructor - text with an icon
 82     public StatusPane(String text, Icon icon) {
 83       super(text, icon, LEFT);
 84       setupPane();
 85     }
 86 
 87     // Helper method for use by constructors
 88     private void setupPane() {
 89       setBackground(Color.LIGHT_GRAY);                                  // Set background color
 90       setForeground(Color.BLACK);                                       // Set foreground color
 91       setFont(paneFont);                                                // Set the fixed font
 92       setBorder(BorderFactory.createCompoundBorder(
 93         BorderFactory.createBevelBorder(BevelBorder.LOWERED),           // Outside border
 94         BorderFactory.createEmptyBorder(0,5,0,3)));                     // Inside border
 95       setPreferredSize(new Dimension(80,20));
 96     }
 97 
 98     // Font for pane text
 99     private Font paneFont = new Font("Serif", Font.PLAIN, 10);
100   }
101 }
View Code

7、视图类:

  1 import javax.swing.*;
  2 import java.util.*;
  3 import java.awt.*;
  4 import java.awt.event.*;
  5 import javax.swing.event.MouseInputAdapter;
  6 import static Constants.SketcherConstants.*;
  7 import java.awt.geom.Line2D;
  8 
  9 @SuppressWarnings("serial")
 10 public class SketcherView extends JComponent implements Observer {
 11   public SketcherView(Sketcher theApp) {
 12     this.theApp = theApp;
 13     MouseHandler handler = new MouseHandler();                          // create the mouse listener
 14     addMouseListener(handler);                                          // Listen for button events
 15     addMouseMotionListener(handler);                                    // Listen for motion events
 16 
 17     // Add the pop-up menu items
 18     JMenuItem moveItem = elementPopup.add(new JMenuItem("Move"));
 19     JMenuItem deleteItem = elementPopup.add(new JMenuItem("Delete"));
 20     JMenuItem rotateItem = elementPopup.add(new JMenuItem("Rotate"));
 21     JMenuItem sendToBackItem = elementPopup.add(new JMenuItem("Send-to-back"));
 22 
 23     // Create the menu item listeners
 24     moveItem.addActionListener(new ActionListener(){
 25       public void actionPerformed(ActionEvent e){
 26         mode = MOVE;
 27         selectedElement = highlightElement;
 28       }
 29     });
 30     deleteItem.addActionListener(new ActionListener(){
 31       public void actionPerformed(ActionEvent e){
 32         deleteElement();
 33       }
 34     });
 35     rotateItem.addActionListener(new ActionListener(){
 36       public void actionPerformed(ActionEvent e){
 37         mode = ROTATE;
 38         selectedElement = highlightElement;
 39       }
 40     });
 41     sendToBackItem.addActionListener(new ActionListener(){
 42       public void actionPerformed(ActionEvent e){
 43         sendToBack();                                                   // Handle the send-to-back event
 44       }
 45     });
 46   }
 47 
 48   // Send-to Back operation
 49   private void sendToBack() {
 50     if(highlightElement != null) {
 51       SketcherModel sketch = theApp.getModel();
 52       if(sketch.remove(highlightElement)) {
 53         sketch.add(highlightElement);
 54       } else {
 55         JOptionPane.showMessageDialog(
 56                         SketcherView.this,"Element not found to remove.",
 57                         "Remove Element from Sketch", JOptionPane.ERROR_MESSAGE);
 58       }
 59     }
 60   }
 61 
 62   // Delete element operation
 63   private void deleteElement() {
 64     if(highlightElement != null) {
 65       if(!theApp.getModel().remove(highlightElement)) {
 66         JOptionPane.showMessageDialog(
 67                         SketcherView.this,"Element not found to remove.",
 68                         "Remove Element from Sketch", JOptionPane.ERROR_MESSAGE);
 69       }
 70       highlightElement = null;
 71     }
 72   }
 73 
 74   // Method called by Observable object when it changes
 75   public void update(Observable o, Object rectangle) {
 76     if(rectangle != null) {
 77       repaint((java.awt.Rectangle)rectangle);
 78     } else {
 79       repaint();
 80     }
 81   }
 82 
 83   // Method to draw on the view
 84   @Override
 85   public void paint(Graphics g) {
 86     Graphics2D g2D = (Graphics2D)g;                                     // Get a 2D device context
 87     for(Element element: theApp.getModel()) {                           // For each element in the model
 88       element.draw(g2D);                                                // ...draw the element
 89     }
 90   }
 91 
 92   class MouseHandler extends MouseInputAdapter {
 93     @Override
 94     public void mousePressed(MouseEvent e)  {
 95       start = e.getPoint();                                             // Save the cursor position in start
 96       buttonState = e.getButton();                                      // Record which button was pressed
 97 
 98       if(showContextMenu(e)) {
 99         start = null;
100         buttonState = MouseEvent.NOBUTTON;
101         return;
102       }
103 
104       if(theApp.getWindow().getElementType() == TEXT && mode == NORMAL) return;
105 
106       // Initialize rotation angles when mode is ROTATE
107       if(mode == ROTATE && selectedElement != null) {
108         oldAngle = selectedElement.getRotation();
109         angle = 0.0;
110       }
111 
112       if(buttonState == MouseEvent.BUTTON1 && mode == NORMAL) {
113         g2D = (Graphics2D)getGraphics();                                // Get graphics context
114         g2D.setXORMode(getBackground());                                // Set XOR mode
115       }
116     }
117 
118 
119     // Show the context menu when an element is highlighted
120     private boolean showContextMenu(MouseEvent e) {
121       if(e.isPopupTrigger()){
122         if(last != null) {                                              // If mouse was dragged
123           start = last;                                                 // show popup at last cursor position
124         }
125         if(highlightElement == null) {                                  // If there is no highlighted element
126           // Show the  popup menu from the app window
127           theApp.getWindow().getPopup().show(SketcherView.this, start.x, start.y);
128         } else {                                                        // Otherwise...
129           // Show the element operations context menu
130           elementPopup.show(SketcherView.this, start.x, start.y);
131         }
132         return true;
133       }
134       return false;
135     }
136 
137     @Override
138     public void mouseDragged(MouseEvent e) {
139       last = e.getPoint();                                              // Save cursor position
140       if(theApp.getWindow().getElementType() == TEXT && mode == NORMAL) return;
141 
142       // Select operation based on sketching mode
143       switch(mode){
144         case NORMAL:
145           // Creating an element
146           if(buttonState == MouseEvent.BUTTON1) {
147             if(tempElement == null) {                                   // Is there an element?
148               tempElement = Element.createElement(                      // No, so create one
149                                      theApp.getWindow().getElementType(),
150                                      theApp.getWindow().getElementColor(),
151                                      start, last);
152             } else {
153               tempElement.draw(g2D);                                    // Yes draw to erase it
154               tempElement.modify(start, last);                          // Now modify it
155             }
156             tempElement.draw(g2D);                                      // and draw it
157          }
158          break;
159        case MOVE:
160          // Moving an element
161          if(buttonState == MouseEvent.BUTTON1 && selectedElement != null) {
162             selectedElement.move(last.x-start.x, last.y-start.y);       // Move it
163             repaint();
164             start = last;                                               // Make start current point
165          }
166          break;
167        case ROTATE:
168          // Rotating an element
169          if(buttonState == MouseEvent.BUTTON1 && selectedElement != null) {
170             angle += getAngle(selectedElement.getPosition(), start, last);
171             if(angle != 0.0) {                                          // If there is rotation
172               selectedElement.setRotation(oldAngle + angle);            // Rotate the element
173               repaint();                                                // Repaint the view
174               start = last;                                             // last is start next time
175             }
176          }
177          break;
178       }
179     }
180 
181     // Helper method for calculating the rotation angle
182     double getAngle(Point position, Point start, Point last) {
183       // Get perpendicular distance from last to line from position to start
184       double perp = Line2D.ptLineDist(position.x, position.y,
185                                       last.x, last.y, start.x, start.y);
186 
187       // Get the distance from position to start
188       double hypotenuse = position.distance(start);
189 
190       if(perp < 1.0 || hypotenuse < 1.0) return 0.0;                    // Ensure sensible values
191 
192       // Angle is the arc sine of perp/hypotenuse. Clockwise is positive angle
193       return -Line2D.relativeCCW(position.x, position.y, start.x, start.y,
194                                  last.x, last.y)*Math.asin(perp/hypotenuse);
195     }
196 
197     @Override
198     public void mouseReleased(MouseEvent e) {
199       if(mode == MOVE || mode == ROTATE) {
200         selectedElement = null;
201         start = last = null;
202         mode = NORMAL;
203         return;
204       }
205 
206       if(showContextMenu(e)) {
207         start = last = null;
208         return;
209       }
210 
211       // Check for TEXT being the element type
212       if(theApp.getWindow().getElementType() == TEXT && mode == NORMAL) {
213         if(last != null) {
214           start = last = null;
215         }
216         return;
217       }
218 
219       if(e.getButton() == MouseEvent.BUTTON1) {
220         buttonState = MouseEvent.NOBUTTON;                              // Reset the button state
221 
222         if(tempElement != null) {                                       // If there is an element...
223           theApp.getModel().add(tempElement);                           // ...add it to the model...
224           tempElement = null;                                           // ...and reset the field
225         }
226         if(g2D != null) {                                               // If there抯 a graphics context
227           g2D.dispose();                                                // ...release the resource...
228           g2D = null;                                                   // ...and reset field to null
229         }
230         start = last = null;                                            // Remove any points
231         mode = NORMAL;                                                  // Always normal after mouse released
232       }
233     }
234 
235     @Override
236     public void mouseClicked(MouseEvent e) {
237       // Only if it's TEXT and button 1 was clicked
238       if(theApp.getWindow().getElementType() == TEXT &&
239                                          buttonState == MouseEvent.BUTTON1) {
240         String text = JOptionPane.showInputDialog(
241                             theApp.getWindow(),"Enter Input:",
242                             "Create Text Element", JOptionPane.PLAIN_MESSAGE);
243 
244         if(text != null && !text.isEmpty()) {                // Only if text was entered
245           g2D = (Graphics2D)getGraphics();
246           tempElement = new Element.Text(text,
247                                          start,
248                                          theApp.getWindow().getElementColor(),
249                                          g2D.getFontMetrics(theApp.getWindow().getFont()));
250           g2D.dispose();
251           g2D = null;
252           if(tempElement != null) {
253             theApp.getModel().add(tempElement);
254           }
255         }
256         tempElement = null;                                             // Reset for next element creation
257         start = null;                                                   // Reset for next element
258       }
259     }
260 
261     // Handle mouse move events
262     @Override
263     public void mouseMoved(MouseEvent e) {
264       Point cursor = e.getPoint();                                      // Get current cursor position
265 
266       for(Element element : theApp.getModel())  {                       // Go through the list...
267         if(element.getBounds().contains(cursor)) {                      // ....under the cursor
268           if(element==highlightElement) {                               // If it's already highlighted
269             return;                                                     // we are done
270           }
271 
272           // Un-highlight any existing highlighted element
273           if(highlightElement!= null) {                                 // If an element is highlighted
274             highlightElement.setHighlighted(false);                     // un-highlight it and
275             repaint(highlightElement.getBounds());                      //... redraw it
276           }
277 
278           element.setHighlighted(true);                                 // Set highlight for new element
279           highlightElement = element;                                   // Store new highlighted element
280             repaint(highlightElement.getBounds());
281           return;
282         }
283       }
284 
285       // Here there is no element under the cursor so...
286       if(highlightElement!=null)   {                                    // If an element is highlighted...
287         highlightElement.setHighlighted(false);                         // ...turn off highlighting...
288         repaint(highlightElement.getBounds());                          // ... and redraw the element
289         highlightElement = null;                                        // No element highlighted
290       }
291     }
292 
293     @Override
294     public void mouseEntered(MouseEvent e) {
295       setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
296     }
297 
298     @Override
299     public void mouseExited(MouseEvent e) {
300       setCursor(Cursor.getDefaultCursor());
301     }
302 
303     private Point start;                                                // Stores cursor position on press
304     private Point last;                                                 // Stores cursor position on drag
305     private Element tempElement = null;                                 // Stores a temporary element
306     private int buttonState = MouseEvent.NOBUTTON;                      // Records button state
307     private Graphics2D g2D = null;                                      // Temporary graphics context
308    }
309 
310   private Sketcher theApp;                                              // The application object
311   private Element highlightElement;                                     // Highlighted element
312   private Element selectedElement;                                      // Element for move or rotate operation
313   private double oldAngle = 0.0;                                        // Initial element rotation
314   private double angle = 0.0;                                           // Additional rotation
315 
316   // Element operations context menu
317   private JPopupMenu elementPopup = new JPopupMenu("Element Operations");
318 
319   private String mode = NORMAL;                                         // Sketching mode
320 }
View Code

8、Sketcher类:

 1 // Sketching application
 2 import javax.swing.*;
 3 import java.awt.*;
 4 import java.awt.event.*;
 5 
 6 public class Sketcher {
 7   public static void main(String[] args) {
 8      theApp = new Sketcher();                                           // Create the application object
 9    SwingUtilities.invokeLater(new Runnable() {
10             public void run() {
11                           theApp.createGUI();                           // Call GUI creator
12             }
13         });
14   }
15 
16   // Method to create the application GUI
17   private void createGUI() {
18     window = new SketcherFrame("Sketcher", this);                       // Create the app window
19     Toolkit theKit = window.getToolkit();                               // Get the window toolkit
20     Dimension wndSize = theKit.getScreenSize();                         // Get screen size
21 
22     // Set the position to screen center & size to half screen size
23     window.setSize(wndSize.width/2, wndSize.height/2);                  // Set window size
24     window.setLocationRelativeTo(null);                                 // Center window
25 
26     window.addWindowListener(new WindowHandler());                      // Add window listener
27 
28     sketch = new SketcherModel();                                       // Create the model
29     view = new SketcherView(this);                                      // Create the view
30     sketch.addObserver(view);                                           // Register view with the model
31     window.getContentPane().add(view, BorderLayout.CENTER);
32     window.setVisible(true);
33   }
34 
35   // Return a reference to the application window
36   public SketcherFrame getWindow() {
37      return window;
38   }
39 
40   // Return a reference to the model
41   public SketcherModel getModel() {
42      return sketch;
43   }
44 
45   // Return a reference to the view
46   public SketcherView getView() {
47      return view;
48   }
49 
50   // Handler class for window events
51   class WindowHandler extends WindowAdapter {
52     // Handler for window closing event
53     @Override
54     public void windowClosing(WindowEvent e) {
55       // Code to be added here...
56     }
57   }
58 
59   private SketcherModel sketch;                                         // The data model for the sketch
60   private SketcherView view;                                            // The view of the sketch
61   private SketcherFrame window;                                         // The application window
62   private static Sketcher theApp;                                       // The application object
63 }
View Code


 

原文地址:https://www.cnblogs.com/mannixiang/p/3500198.html