zoukankan      html  css  js  c++  java
  • 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


     

  • 相关阅读:
    Algorithm Gossip (48) 上三角、下三角、对称矩阵
    .Algorithm Gossip (47) 多维矩阵转一维矩阵
    Algorithm Gossip (46) 稀疏矩阵存储
    Algorithm Gossip (45) 费氏搜寻法
    Algorithm Gossip (44) 插补搜寻法
    Algorithm Gossip (43) 二分搜寻法
    Algorithm Gossip (42) 循序搜寻法(使用卫兵)
    Algorithm Gossip (41) 基数排序法
    Algorithm Gossip (40) 合并排序法
    AlgorithmGossip (39) 快速排序法 ( 三 )
  • 原文地址:https://www.cnblogs.com/mannixiang/p/3500198.html
Copyright © 2011-2022 走看看