HW#2 --- last modified January 16 2019 00:35:12..A solution set is posted here. Due date: Oct. 1, 2001 start of class ========= Files to be submitted: cs146sec6hw2file1.java (sec 8 if you're in sec 8) ====================== This as usual should be submitted via e-mail. Book problem 4.9 should be turned in on paper start of class. Purpose: To gain experience with stacks and binary search trees. ======== Specification: ============== In addition to problem 4.9, you will write a Java application to display pictures written in ShML (Shape Mark-up Language). ShML is a language I invented for this homework similar to HTML. Your application will be tested from the command prompt with a line like: java cs146sec6hw2file1 shmlfile Your program should then read in the file in its args[0] and try to parse the ShML file in it. If the file is parsable your application should then open a JFrame and draw the ShML picture in it on a black background. Make sure you have a WindowListener so this window can be clicked closed. ShML has three pairs of tags: <square> </square> <circle> </circle> <triangle> </triangle> The meaning of a pair of tags is to draw that kind of shape in the current enclosing shape. Triangles should be drawn in red; circles should be drawn in green; and squares should be drawn in blue. If there is no enclosing shape the shape should be drawn directly on the frame's background. For example, if the ShML file was the following: <square> <circle> </circle> <triangle> </triangle> </square> <square> </square> then two non-overlapping squares would be drawn centered on the JFrame. In the interior of the first square, would be drawn in a non-overlapping manner a circle and triangle. Obviously, shapes drawn interior to other shapes must be scaled appropriately to make them fit inside. The details of the scaling and insuring the shapes interior to a given shape do not overlap are left up to you. You are required to use java.util.Stack to handle the parsing of the file. You may also find the StringTokenizer class useful in writing your application. You can use the Graphics class' method fillPolygon to draw triangles. If the file involves any non-space symbols other than those in tags or if the open and close tags mismatch then your application should output: The provided file was not a valid ShML file. If args[0] was empty a message saying so should be given as well. An example of a file with mismatched tags is: <square> <circle> </circle> </triangle> </square> As another example of what an ShML image might look like the file: <triangle> <circle> <square> <circle> </circle> </square> </circle> <square> </square> <circle> </circle> </triangle> in my version produces the output: Useful Hints: ============= (0) Make sure to take advantage of the Java 2 Platform Class Library link off of the class homepage. (1) JFrame extends Component so has a paint(Graphics g) method. You should override this method to do your drawing of shapes. (2) You may want to make classes for ShMLCircle, ShMLSquare, and ShMLTriangle. Each of which extend a common class ShMLShape. An ShMLShape could contain a LinkedList object (in java.util) to which you could add other ShMLShape's. ShMLShape's could have a draw method which given a Graphics object g can draw itself and any object on it to g. An ShMLShape can store information on what its bounding rectangle is. When it is drawn it knows to draw itself in this rectangle. It can have a method setRectangle to set this Rectangle. Finally, an ShMLShape obj can have an organize() method which can be called if need be during the draw phase. This method calculates a bounding rectangle for each the ShMLShapes on obj so that these ShMLShapes do not overlap. It does a setRectangle on each of these ShMLShapes then calls their organize() methods. (3) You can read in files using the FileReader and BufferedReader classes. To open a file you can use something like: BufferedReader buf = new BufferedReader( new FileReader(fileName)); Here fileName is a String. To close this file do buf.close(); To read a line, you can do buf.readLine(). This will be null when the end of a file is reached. You should catch FileNotFoundException's and IOException's. (4) You can check if an object is an object of a given class using instanceof. For instance, (obj instanceof ShMLCircle) would return true if obj is an object of class ShMLCircle. (5) When using Stack or LinkedList remember you have to recast the Object back to a subtype (for instance, ShMLShape) if you want the functionality of that subtype. (6) Remember a String variable is a reference. To actually check if two String's are equal use to s1.equals(s2) where s1 and s2 are String's. Below is a short example application (from class) that extends JFrame: /* LineDrawer - a simple application to draw a line in a window. */ import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import javax.swing.*; import java.util.*; import java.io.*; /** Run from the command line with a command like: java LineDrawer filename This LineDrawer reads in two point from the file filename and then opens a JFrame where the line given by these points is drawn. @author cpollett @version 1.0 */ public class LineDrawer extends JFrame { public static final int DEFAULT_X_SZ = 400; //dimensions of window public static final int DEFAULT_Y_SZ = 400; Polygon line = new Polygon(); // will be used to contain our line /** This constructor takes opens the file named name and tries to read in a line. Background and size of window are also set. */ public LineDrawer( String name) { super("LineDrawer"); readLine(name); setSize(DEFAULT_X_SZ, DEFAULT_Y_SZ); setBackground(Color.black); } /** This method will be called by the run-time system when it wants to draw the interior of the JFrame. Since we aren't doing any animation this program directly overrides paint to draw the line. For animations, a better way is to add a JPanel to the JFrame and override the JPanel's paintComponent(Graphics g) method. This avoid flicker. */ public void paint(Graphics g) { g.setColor(Color.blue); g.drawPolygon(line); } /* This functions open the file fileName and tries to read two Points from it. These Point's are added to the Polygon line. */ private void readLine(String fileName) { String mesg = "File did not contain enough points"; Point point = new Point(-1,-1); //we give some dummy values Point point2 = new Point(-1,-1);//so defined on all syntactic paths try { BufferedReader buf= new BufferedReader( new FileReader(fileName) ); //open a Reader for the file fileName String pt = buf.readLine(); //read in first Point as String point = parsePoint(pt); //convert String to Point String pt2 = buf.readLine(); //now do the same for second point point2 = parsePoint(pt2); buf.close(); } catch(FileNotFoundException fe) { System.err.println("File not found"); System.exit(1); } catch(IOException ie) { System.err.println("An I/O Exception occurred:"+ie.toString()); System.exit(1); } catch(Exception ee) { System.err.println(mesg); System.exit(1); } line.addPoint(point.x, point.y); line.addPoint(point2.x, point2.y); } /* This function takes a String and tries to determins a Point object from it. The idea is a String like: 10,20 is supposed to represent the point (10,20). */ private Point parsePoint(String pt) throws Exception /* we have learned how to define our own exceptions yet so I just throw an Exception */ { int x=-1; //dummy values so defined on all syntactic paths. int y=-1; StringTokenizer tokens = new StringTokenizer(pt,","); if(tokens.hasMoreTokens()) //get first coordinate { x = Integer.parseInt(tokens.nextToken()); } else throw new Exception(); if(tokens.hasMoreTokens()) //get second coordinate { y = Integer.parseInt(tokens.nextToken()); } else throw new Exception(); return new Point(x,y); } // Main entry point public static void main(String[] args) { if( args.length == 0 ) { System.err.println("You need to give as a comand line "+ "argument an point file."); System.exit(1); } LineDrawer app= new LineDrawer(args[0]); app.show(); //show the JFrame on the screen app.addWindowListener( /* handle close window events with this anonymous inner class */ new WindowAdapter() { public void windowClosing( WindowEvent e) { System.exit(0); } } ); } } Point Breakdown =============== Coding guidelines followed............1pt WindowListener used...................1pt Stacks used in a constructive way.....1pt Program reads in ShML file............1pt Draws shapes correctly................1pt Bad or no input file case handled.....1pt Problem 4.9a..........................1pt Problem 4.9b..........................1pt ========================================= Total.................................8pts A solution set is posted here. |