控制台程序。
在模型中表示数据视图的类用来显示草图并处理用户的交互操作,所以这种类把显示方法和草图控制器合并在一起。不专用于某个视图的通用GUI创建和操作在SketcherFrame类中处理。
模型对象包含构成草图的文本和图形。模型类可以称为SketcherModel,表示模型视图的类可以称为SketcherView.
应用程序对象全面负责管理程序涉及的其他对象之间的链接。只要应用程序类能使每个对象可用,可以访问应用程序对象的任何对象就都要与其他对象进行通信。因此,应用程序对象是对象之间的通信通道。
注意:SketcherFrame不是视图类,这个类仅仅定义应用程序窗口及其关联的GUI组件。创建SketcherView对象时,应把SketcherView对象插入到SketcherFrame对象的内容面板中,并使用内容面板的布局管理器进行管理。通过将视图类与应用程序类分开定义,就可以把草图的视图与用于和程序交互的菜单及其他组件分开。这么做的优点是显示草图的区域能拥有自己的坐标系统,这种坐标系统独立于应用程序窗口的坐标系统。
1、SketcherModel类:
1 import java.io.Serializable; 2 import java.util.Observable; 3 4 public class SketcherModel extends Observable implements Serializable { 5 // Detail of the rest of class to be filled in later... 6 private final static long serialVersionUID = 1001L; 7 }
这个类可以串行化,因为我们希望把草图保存到文件中。SketcherModel类扩展了Observable类,所以可以使用这个类把视图类注册为观察器,并将视图的任何变化自动通知给模型。当草图拥有多个视图时,这个功能就会很有用。
2、SketcherView类:
1 import javax.swing.JComponent; 2 import java.util.*; 3 import java.awt.*; 4 5 @SuppressWarnings("serial") 6 public class SketcherView extends JComponent implements Observer { 7 public SketcherView(Sketcher theApp) { 8 this.theApp = theApp; 9 } 10 11 // Method called by Observable object when it changes 12 public void update(Observable o, Object rectangle) { 13 // Code to respond to changes in the model... 14 } 15 16 // Method to draw on the view 17 @Override 18 public void paint(Graphics g) { 19 // Temporary code... 20 Graphics2D g2D = (Graphics2D)g; // Get a Java 2D device context 21 22 g2D.setPaint(Color.RED); // Draw in red 23 g2D.draw3DRect(50, 50, 150, 100, true); // Draw a raised 3D rectangle 24 g2D.drawString("A nice 3D rectangle", 60, 100); // Draw some text 25 } 26 27 private Sketcher theApp; // The application object 28 }
视图需要访问模型才能显示,但构造函数不是在视图中保存对模型的引用,而是让应用程序对象通过参数把引用传送给视图。视图对象可以使用应用程序对象来访问模型对象,如果需要,还可以访问应用程序窗口。
视图注册为模型的观察器。如果存在完全不同的对象表示模型,例如要加载新的文件,视图对象就会自动获得模型已发生改变的通知,并且能重绘视图作为响应。
3、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 }
Sketcher类中的新方法返回对应用程序窗口、模型和视图的引用,所以在Sketcher应用程序代码的任何地方,只要有对应用程序对象的引用,就可以访问它们。
在Sketcher类的createGUI()方法中创建完模型和视图对象后,就把视图注册为模型的观察器,让模型在发生变化时通知视图。
4、SketcherFrame类:

// Frame for the Sketcher application import javax.swing.*; import javax.swing.border.*; import java.awt.event.*; import java.awt.*; import static java.awt.event.InputEvent.*; import static java.awt.AWTEvent.*; import static java.awt.Color.*; import static Constants.SketcherConstants.*; import static javax.swing.Action.*; @SuppressWarnings("serial") public class SketcherFrame extends JFrame { // Constructor public SketcherFrame(String title, Sketcher theApp) { setTitle(title); // Set the window title this.theApp = theApp; // Save app. object reference setJMenuBar(menuBar); // Add the menu bar to the window setDefaultCloseOperation(EXIT_ON_CLOSE); // Default is exit the application createFileMenu(); // Create the File menu createElementMenu(); // Create the element menu createColorMenu(); // Create the element menu createToolbar(); toolBar.setRollover(true); getContentPane().add(toolBar, BorderLayout.NORTH); } // Create File menu item actions private void createFileMenuActions() { newAction = new FileAction("New", 'N', CTRL_DOWN_MASK); openAction = new FileAction("Open", 'O', CTRL_DOWN_MASK); closeAction = new FileAction("Close"); saveAction = new FileAction("Save", 'S', CTRL_DOWN_MASK); saveAsAction = new FileAction("Save As..."); printAction = new FileAction("Print", 'P', CTRL_DOWN_MASK); exitAction = new FileAction("Exit", 'X', CTRL_DOWN_MASK); // Initialize the array FileAction[] actions = {openAction, closeAction, saveAction, saveAsAction, printAction, exitAction}; fileActions = actions; // Add toolbar icons newAction.putValue(LARGE_ICON_KEY, NEW24); openAction.putValue(LARGE_ICON_KEY, OPEN24); saveAction.putValue(LARGE_ICON_KEY, SAVE24); saveAsAction.putValue(LARGE_ICON_KEY, SAVEAS24); printAction.putValue(LARGE_ICON_KEY, PRINT24); // Add menu item icons newAction.putValue(SMALL_ICON, NEW16); openAction.putValue(SMALL_ICON, OPEN16); saveAction.putValue(SMALL_ICON, SAVE16); saveAsAction.putValue(SMALL_ICON,SAVEAS16); printAction.putValue(SMALL_ICON, PRINT16); // Add tooltip text newAction.putValue(SHORT_DESCRIPTION, "Create a new sketch"); openAction.putValue(SHORT_DESCRIPTION, "Read a sketch from a file"); closeAction.putValue(SHORT_DESCRIPTION, "Close the current sketch"); saveAction.putValue(SHORT_DESCRIPTION, "Save the current sketch to file"); saveAsAction.putValue(SHORT_DESCRIPTION, "Save the current sketch to a new file"); printAction.putValue(SHORT_DESCRIPTION, "Print the current sketch"); exitAction.putValue(SHORT_DESCRIPTION, "Exit Sketcher"); } // Create the File menu private void createFileMenu() { JMenu fileMenu = new JMenu("File"); // Create File menu fileMenu.setMnemonic('F'); // Create shortcut createFileMenuActions(); // Create Actions for File menu item // Construct the file drop-down menu fileMenu.add(newAction); // New Sketch menu item fileMenu.add(openAction); // Open sketch menu item fileMenu.add(closeAction); // Close sketch menu item fileMenu.addSeparator(); // Add separator fileMenu.add(saveAction); // Save sketch to file fileMenu.add(saveAsAction); // Save As menu item fileMenu.addSeparator(); // Add separator fileMenu.add(printAction); // Print sketch menu item fileMenu.addSeparator(); // Add separator fileMenu.add(exitAction); // Print sketch menu item menuBar.add(fileMenu); // Add the file menu } // Create Element menu actions private void createElementTypeActions() { lineAction = new TypeAction("Line", LINE, 'L', CTRL_DOWN_MASK); rectangleAction = new TypeAction("Rectangle", RECTANGLE, 'R', CTRL_DOWN_MASK); circleAction = new TypeAction("Circle", CIRCLE,'C', CTRL_DOWN_MASK); curveAction = new TypeAction("Curve", CURVE,'U', CTRL_DOWN_MASK); // Initialize the array TypeAction[] actions = {lineAction, rectangleAction, circleAction, curveAction}; typeActions = actions; // Add toolbar icons lineAction.putValue(LARGE_ICON_KEY, LINE24); rectangleAction.putValue(LARGE_ICON_KEY, RECTANGLE24); circleAction.putValue(LARGE_ICON_KEY, CIRCLE24); curveAction.putValue(LARGE_ICON_KEY, CURVE24); // Add menu item icons lineAction.putValue(SMALL_ICON, LINE16); rectangleAction.putValue(SMALL_ICON, RECTANGLE16); circleAction.putValue(SMALL_ICON, CIRCLE16); curveAction.putValue(SMALL_ICON, CURVE16); // Add tooltip text lineAction.putValue(SHORT_DESCRIPTION, "Draw lines"); rectangleAction.putValue(SHORT_DESCRIPTION, "Draw rectangles"); circleAction.putValue(SHORT_DESCRIPTION, "Draw circles"); curveAction.putValue(SHORT_DESCRIPTION, "Draw curves"); } // Create the Elements menu private void createElementMenu() { createElementTypeActions(); elementMenu = new JMenu("Elements"); // Create Elements menu elementMenu.setMnemonic('E'); // Create shortcut createRadioButtonDropDown(elementMenu, typeActions, lineAction); menuBar.add(elementMenu); // Add the element menu } // Create Color menu actions private void createElementColorActions() { redAction = new ColorAction("Red", RED, 'R', CTRL_DOWN_MASK|ALT_DOWN_MASK); yellowAction = new ColorAction("Yellow", YELLOW, 'Y', CTRL_DOWN_MASK|ALT_DOWN_MASK); greenAction = new ColorAction("Green", GREEN, 'G', CTRL_DOWN_MASK|ALT_DOWN_MASK); blueAction = new ColorAction("Blue", BLUE, 'B', CTRL_DOWN_MASK|ALT_DOWN_MASK); // Initialize the array ColorAction[] actions = {redAction, greenAction, blueAction, yellowAction}; colorActions = actions; // Add toolbar icons redAction.putValue(LARGE_ICON_KEY, RED24); greenAction.putValue(LARGE_ICON_KEY, GREEN24); blueAction.putValue(LARGE_ICON_KEY, BLUE24); yellowAction.putValue(LARGE_ICON_KEY, YELLOW24); // Add menu item icons redAction.putValue(SMALL_ICON, RED16); blueAction.putValue(SMALL_ICON, BLUE16); greenAction.putValue(SMALL_ICON, GREEN16); yellowAction.putValue(SMALL_ICON, YELLOW16); // Add tooltip text redAction.putValue(SHORT_DESCRIPTION, "Draw in red"); blueAction.putValue(SHORT_DESCRIPTION, "Draw in blue"); greenAction.putValue(SHORT_DESCRIPTION, "Draw in green"); yellowAction.putValue(SHORT_DESCRIPTION, "Draw in yellow"); } // Create the Color menu private void createColorMenu() { createElementColorActions(); colorMenu = new JMenu("Color"); // Create Elements menu colorMenu.setMnemonic('C'); // Create shortcut createRadioButtonDropDown(colorMenu, colorActions, blueAction); menuBar.add(colorMenu); // Add the color menu } // Menu creation helper private void createRadioButtonDropDown(JMenu menu, Action[] actions, Action selected) { ButtonGroup group = new ButtonGroup(); JRadioButtonMenuItem item = null; for(Action action : actions) { group.add(menu.add(item = new JRadioButtonMenuItem(action))); if(action == selected) { item.setSelected(true); // This is default selected } } } // Create toolbar buttons on the toolbar private void createToolbar() { for(FileAction action: fileActions){ if(action != exitAction && action != closeAction) addToolbarButton(action); // Add the toolbar button } toolBar.addSeparator(); // Create Color menu buttons for(ColorAction action:colorActions){ addToolbarButton(action); // Add the toolbar button } toolBar.addSeparator(); // Create Elements menu buttons for(TypeAction action:typeActions){ addToolbarButton(action); // Add the toolbar button } } // Create and add a toolbar button private void addToolbarButton(Action action) { JButton button = new JButton(action); // Create from Action button.setBorder(BorderFactory.createCompoundBorder( // Add button border new EmptyBorder(2,5,5,2), // Outside border BorderFactory.createRaisedBevelBorder())); // Inside border button.setHideActionText(true); // No label on the button toolBar.add(button); // Add the toolbar button } // Set radio button menu checks private void setChecks(JMenu menu, Object eventSource) { if(eventSource instanceof JButton){ JButton button = (JButton)eventSource; Action action = button.getAction(); for(int i = 0 ; i < menu.getItemCount() ; ++i) { JMenuItem item = menu.getItem(i); item.setSelected(item.getAction() == action); } } } // Inner class defining Action objects for File menu items class FileAction extends AbstractAction { // Create action with a name FileAction(String name) { super(name); } // Create action with a name and accelerator FileAction(String name, char ch, int modifiers) { super(name); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(ch, modifiers)); // Now find the character to underline int index = name.toUpperCase().indexOf(ch); if(index != -1) { putValue(DISPLAYED_MNEMONIC_INDEX_KEY, index); } } // Event handler public void actionPerformed(ActionEvent e) { // You will add action code here eventually... } } // Inner class defining Action objects for Element type menu items class TypeAction extends AbstractAction { // Create action with just a name property TypeAction(String name, int typeID) { super(name); this.typeID = typeID; } // Create action with a name and an accelerator private TypeAction(String name,int typeID, char ch, int modifiers) { this(name, typeID); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(ch, modifiers)); // Now find the character to underline int index = name.toUpperCase().indexOf(ch); if(index != -1) { putValue(DISPLAYED_MNEMONIC_INDEX_KEY, index); } } public void actionPerformed(ActionEvent e) { elementType = typeID; setChecks(elementMenu, e.getSource()); } private int typeID; } // Handles color menu items class ColorAction extends AbstractAction { // Create an action with a name and a color public ColorAction(String name, Color color) { super(name); this.color = color; } // Create an action with a name, a color, and an accelerator public ColorAction(String name, Color color, char ch, int modifiers) { this(name, color); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(ch, modifiers)); // Now find the character to underline int index = name.toUpperCase().indexOf(ch); if(index != -1) { putValue(DISPLAYED_MNEMONIC_INDEX_KEY, index); } } public void actionPerformed(ActionEvent e) { elementColor = color; setChecks(colorMenu, e.getSource()); } private Color color; } // File actions private FileAction newAction, openAction, closeAction, saveAction, saveAsAction, printAction, exitAction; private FileAction[] fileActions; // File actions as an array // Element type actions private TypeAction lineAction, rectangleAction, circleAction, curveAction; private TypeAction[] typeActions; // Type actions as an array // Element color actions private ColorAction redAction, yellowAction,greenAction, blueAction; private ColorAction[] colorActions; // Color actions as an array private JMenuBar menuBar = new JMenuBar(); // Window menu bar private JMenu elementMenu; // Elements menu private JMenu colorMenu; // Color menu private Color elementColor = DEFAULT_ELEMENT_COLOR; // Current element color private int elementType = DEFAULT_ELEMENT_TYPE; // Current element type private JToolBar toolBar = new JToolBar(); // Window toolbar private Sketcher theApp; // The application object }
5、自定义常量包SketcherConstants:

1 // Defines application wide constants 2 package Constants; 3 import java.awt.Color; 4 import javax.swing.*; 5 6 public class SketcherConstants { 7 // Path for images 8 public final static String imagePath = "E:/JavaProject/BeginningJava/Images/"; 9 10 // Toolbar icons 11 public final static Icon NEW24 = new ImageIcon(imagePath + "New24.gif"); 12 public final static Icon OPEN24 = new ImageIcon(imagePath + "Open24.gif"); 13 public final static Icon SAVE24 = new ImageIcon(imagePath + "Save24.gif"); 14 public final static Icon SAVEAS24 = new ImageIcon(imagePath + "SaveAs24.gif"); 15 public final static Icon PRINT24 = new ImageIcon(imagePath + "Print24.gif"); 16 17 public final static Icon LINE24 = new ImageIcon(imagePath + "Line24.gif"); 18 public final static Icon RECTANGLE24 = new ImageIcon(imagePath + "Rectangle24.gif"); 19 public final static Icon CIRCLE24 = new ImageIcon(imagePath + "Circle24.gif"); 20 public final static Icon CURVE24 = new ImageIcon(imagePath + "Curve24.gif"); 21 22 public final static Icon RED24 = new ImageIcon(imagePath + "Red24.gif"); 23 public final static Icon GREEN24 = new ImageIcon(imagePath + "Green24.gif"); 24 public final static Icon BLUE24 = new ImageIcon(imagePath + "Blue24.gif"); 25 public final static Icon YELLOW24 = new ImageIcon(imagePath + "Yellow24.gif"); 26 27 // Menu item icons 28 public final static Icon NEW16 = new ImageIcon(imagePath + "new16.gif"); 29 public final static Icon OPEN16 = new ImageIcon(imagePath + "Open16.gif"); 30 public final static Icon SAVE16 = new ImageIcon(imagePath + "Save16.gif"); 31 public final static Icon SAVEAS16 = new ImageIcon(imagePath + "SaveAs16.gif"); 32 public final static Icon PRINT16 = new ImageIcon(imagePath + "print16.gif"); 33 34 public final static Icon LINE16 = new ImageIcon(imagePath + "Line16.gif"); 35 public final static Icon RECTANGLE16 = new ImageIcon(imagePath + "Rectangle16.gif"); 36 public final static Icon CIRCLE16 = new ImageIcon(imagePath + "Circle16.gif"); 37 public final static Icon CURVE16 = new ImageIcon(imagePath + "Curve16.gif"); 38 39 public final static Icon RED16 = new ImageIcon(imagePath + "Red16.gif"); 40 public final static Icon GREEN16 = new ImageIcon(imagePath + "Green16.gif"); 41 public final static Icon BLUE16 = new ImageIcon(imagePath + "Blue16.gif"); 42 public final static Icon YELLOW16 = new ImageIcon(imagePath + "Yellow16.gif"); 43 44 // Element type definitions 45 public final static int LINE = 101; 46 public final static int RECTANGLE = 102; 47 public final static int CIRCLE = 103; 48 public final static int CURVE = 104; 49 50 // Initial conditions 51 public final static int DEFAULT_ELEMENT_TYPE = LINE; 52 public final static Color DEFAULT_ELEMENT_COLOR = Color.BLUE; 53 }