A Java application with a GUI will typically consist of several components. A popular software design pattern for this type of software is the Model-View-Controller pattern. It separates the application logic from the user interface and the control between the user interface and the application logic.
In a Java application, the model, view, and controller can be implemented in separate classes, or in a single class. The communications between the model and the view can be implemented in several ways as well. There are many MVC tutorials, such as, Java SE Application Design With MVC and Model-View-Controller (MVC) Structure.
This example application is a combination of the textbook's JList example (Figure 14.23) and the mouse drawing example using a JPanel (Figure 14.34).
The whole application is contained in demomvc.zip (javadoc documentation).
The DemoMVC class holds the main method that starts the application. DemoModel implements the model part of the application. DemoView and PaintPanel implement the view part of the application. DemoController implements the controller part of the application.
The following UML diagram shows unidirectional associations because, for example, DemoController has a DemoModel attribute, but not vice versa. A dependency is shown from DemoView to DemoController because DemoView's registerController method has a DemoController parameter.
A DemoModel object has instance variables for storing an array of Points and a color. [A Point object has instance variables x and y that can be directly accessed, e.g., point.x and point.y.] DemoModel also has methods for updating and accessing the points and the color. This implementation has some serious shortcomings that you are encouraged to fix. For example, it would be better to use ArrayList<Point> instead of a fixed-size Point array.
A DemoController object has instance variables for a DemoModel and a DemoView, which are initialized by the constructor. DemoController implements the MouseMotionListener interface (mouseDragged and mouseMoved method) and the ListSelectionListener interface (valueChanged method).
The intent is that the mouseDragged method will be called whenever the user draws with the mouse, and the valueChanged method will be called whenever the user selects a color. The mouseMoved method is needed to implement the MouseMotionListener interface, but does not need any code.
The mouseDragged method adds the point from the MouseEvent to the model and repaints the window. The valueChanged method obtains the selected color from the view (the event object is not very useful, plus the view knows what the colors are), updates the model's color, and repaints the window.
A DemoView object has instance variables for the window's components, plus two class constants for the color selection: an array of Strings to be displayed, and an array of Colors corresponding to the Strings. DemoView is a subclass of JFrame. The constructor organizes the window, and the methods help to coordinate with the controller and the model.
The constructor sets up the window components as follows:
The JFrame consists of two JPanels (PaintPanel is a subclass of JPanel). The PaintPanel is added to the "center" so that it will use up available space. The JList is added to the left/west JPanel, embedded in a JScrollPane.
The registerListener method is used to register the controller with the specific components that the user interacts with. The getSelectedColor method allows the controller to find out what color in the JList was selected by the user.
The paint method might be a little mysterious because there is no paint method call in the code. This method will be called as part of a call to the repaint method (see the methods in DemoController). No code should directly call the paint method. The paint method sets the background color of the JPanel that contains the JList calls super.paint(g) so that all the components will be drawn.
PaintPanel implements the rest of the view. It is used to draw the points that the user has drawn. PaintPanel extends JPanel and overrides the paintComponent method to draw the points. paintComponent is another "mysterious" method; it will be called as part of the repaint call. This method loops through all the Points in the model. Note that model.getPoint(i) returns null if there no Point at index i. For each Point, the fillOval method of the Graphics object g is called. The Graphics class has many useful methods for drawing figures.
The sequence of events that happens when the user drags the mouse in the PaintPanel is as follows:
Note that in this example, DemoModel does not actively update the view. Instead, the controller simply repaints the whole window after the model is updated. An advantage of this approach is that the model can be tested independently of the view. The view does not directly change the model either. An advantage of making all changes come from the controller is that if something changed incorrectly, the controller is the first place to look.
It might be more efficient to only repaint those components that have changed. To do this, whenever the model is updated, the view would be given more information about what was changed, e.g., the view might have methods named pointsWereChanged and colorWasChanged, and then calls repaint only for those components that need to be updated. [Note: your code should not call paintComponent or paint directly, but should call repaint so that the GUI thread will operate correctly. See Section 15.2.]
A simple calculator is contained in calculator.zip (javadoc documentation). This program has two features that you might not have seen yet. One is that each file is declared to be in a package named calculator. In Eclipse, all the source files will be in src/calculator, and all the compiled files will be in bin/calculator. The other features is that this program has an example of a menu.
A simple example to allow one user to play Pong is contained in pong.zip (javadoc documentation). The model is in PongModel, the view is in PongView and PongPanel, and the controller is the rest of the code (except the main method). This example also has package declarations and a menu. This program also has a popup menu (accessible via a right click) and keyboard shortcuts (f, p, and e) for the same menu items. It also keeps track of the size of the window. Possibly all of the controller code could have been put into a single class, but that would be a dubious improvement.
The popup menu has the most unusual flow of control. When the user clicks the mouse, a MouseEvent will be handled by PongPopupController. PongPopupController sends the event to PongView because the view contains the popup menu (the view keeps track of all the components of the window). The checkForTriggerEvent method in PongView will, if appropriate, show the popup menu. If an item is selected from the popup menu, that will result in an ActionEvent that will be handled by PongMenuController. FYI: