• 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


     

  • 相关阅读:
    线性回归和 逻辑回归 的思考(参考斯坦福 吴恩达的课程)
    数据结构算法基础-内部排序算法
    机器学习《test》
    day1.接口测试(概念、Postman、SoapUI、jmeter)
    SQL2000 3核6核 CUP 安装SP4
    SQL常用语句
    SQL SERVER 2000数据库置疑处理
    常用终端命令
    c++ 位操作
    计算机为什么用补码存储数据?
  • 原文地址:https://www.cnblogs.com/mannixiang/p/3500198.html
Copyright © 2020-2023  润新知