CIS-257 Home: http://www.c-jump.com/bcc/c257c/c257syllabus.html
In previous tutorial we discussed 2D rendering and mouse events.
In this tutorial we reorganize the project introducing the MVC architecture.
The new project structure is derived from the model-view-controller design pattern:
The model class provides the data.
The view class is responsible for rendition of the data on the screen.
The controller class makes updates in both the data and the view.
We already have a user interface class named DrawingBox2D. It encapsulates the view of the data model in this demo. However, its current implementation contains the code that has to deal with both the data handling and drawing the trigonometric wave:
public class DrawingBox2D extends javax.swing.JPanel implements MouseListener, MouseMotionListener { //... @Override public void paintComponent(Graphics graph) { //... int oldx = 0; int oldy = 0; for (int x = 0; x < 360; ++x) { int y = (int)( -sin( Math.toRadians(x + degrees) ) * 50 ) + 100; //int y = (int)( -cos( Math.toRadians(x) ) * 50 ) + 100; //int y = (int)( -tan( Math.toRadians(x) ) * 50 ) + 100; //int y = (int) (-1 / tan(Math.toRadians(x + degrees)) * 50) + 100; graph.drawLine(oldx, oldy, x, y); oldx = x; oldy = y; } }//paintComponent }//class DrawingBox2D
This is okay for a tiny demo program, but it is inacceptable for a larger application that needs to be extensible, portable, maintainable, and hopefully, made of reusable parts. A more practical application needs a solution to the following set of problems:
The trigonometric wave generation parameters need to be configurable by the user
The user wants to draw trigonometric functions of different types: sine, cosine, tangent, cotangent, and so on.
The user also wants to add multiple instances of trigonometric functions to the graph.
To make it all possible we must
Separate the data and data-related calculations from the drawing.
Encapsulate the data in a separate Java class, such as WaveSine.
Enable access to the WaveSine and other similar objects via formal interface ITrigWave.
Use a generic collection class, such as ArrayList<ITrigWave> to store multiple instances of the trigonometric waves.
Add a new class named Controller4waves. It is responsible for
providing methods for all user interaction events, such as menu and button clicks
providing methods to return data that may be needed by the current view
What is the interface of a data object that alows graphing a trigonometric function?
The actual drawing is done via series of small continuous line segments between points with coordinates (oldx, oldy) and (x, y):
graph.drawLine( oldx, oldy, x, y );
Therefore, the interface must have a method to calculate every segment and have a "getter" method for each coordinate:
public interface ITrigWave { void calculateNextSegment( int degreeIncrement ); int getDegrees(); // starting degree of the wave int getOldX(); int getOldY(); int getNewX(); int getNewY(); }//interface ITrigWave
The calculateNextSegment() method takes degreeIncrement parameter and adds it to the angle that yields the trigonometric value for each segment.
The interface can then be used like this:
public class DrawingBox2D extends javax.swing.JPanel implements MouseListener, MouseMotionListener { private ITrigWave trigFunction = new WaveSine(); //private ITrigWave trigFunction = new WaveCoine(); //private ITrigWave trigFunction = new WaveTangent(); //private ITrigWave trigFunction = new WaveCotangent(); //... @Override public void paintComponent(Graphics graph) { //... // Prepare to draw: int x = trigFunction.getNewX(); // returns -1 when all segments are processed int y = trigFunction.getNewY(); int oldx = trigFunction.getOldX(); int oldy = trigFunction.getOldY(); // Draw trigonometric funstion while ( x != -1 ) { graph.drawLine(oldx, oldy, x, y); x = trigFunction.getNewX(); y = trigFunction.getNewY(); oldx = trigFunction.getOldX(); oldy = trigFunction.getOldY(); } //... } }//class DrawingBox2D
In each loop iteration trigFunction object yields a tiny segment of the wave. The animation adjustments are made by the calculateNextSegment() calls.
The rest of the code for this intermidiate stage is in demo2Dwave.zip , which contains a complete NetBeans project. The project has classes to draw sine, cosine, tangent, and cotangent. However, we have yet add a controller class to our application.
The Controller4waves class isolates the data form the user interface. At the same time it provides methods to access the data.
The code for the final version of the tutorial is in demo2Dmvc.zip
The main class method FrameDemo2D.main()
creates the instance of the controller class
creates the instance of the window class and passes the reference to the controller class as a parameter
creates some trigonometric wave objects and adds them to the collection of waves in the controller object.
The updated version of the DrawingBox2D.update() method iterates through the collection of waves and updates the starting degree for the trigonometric wave.
The updated version of the DrawingBox2D.paintComponent() method iterates through the collection of waves and draws them in the drawing box.
The final copy of the NetBeans project for this tutorial is posted here: demo2Dmvc.zip