CSE190L Sample Final, Spring 2007 handout #28 1. Inheritance, 30 points. You are to rewrite a pair of classes using inheritance to avoid redundancy. The classes you will rewrite are subclasses of JPanel that draw and label a particular shape. One draws a circle and one draws a rectangle, as in the two panels displayed below.
These are just two examples of a family of shapes that we might want to draw. As with these two, each would be centered within the panel and would be labeled with a title using an 18-point bold Serif font just below the figure. When you compare these two classes, you will find a lot of redundancy. You are to eliminate the redundant code by creating a superclass for these two classes called Picture. You should appropriately declare any method as abstract if the definition of the method varies from one subclass to the next. All data fields of your classes must be declared to be private, although you can introduce protected methods. Below and on the next page are the two classes you are to rewrite. public class Circle extends JPanel { private int radius; public Circle(int radius) { this.radius = radius; } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; Font f = new Font("Serif", Font.BOLD, 18); g2.setFont(f); int centerX = getWidth()/2; int centerY = getHeight()/2; g2.draw(new Ellipse2D.Double(centerX - radius, centerY - radius, 2 * radius, 2 * radius)); g2.fill(new Ellipse2D.Double(centerX, centerY, 3, 3)); String text = "Circle"; FontRenderContext context = g2.getFontRenderContext(); double width = g2.getFont().getStringBounds(text, context).getWidth(); g2.drawString(text, centerX - (int) (width/2), centerY + radius + 18); } } public class Rectangle extends JPanel { private int height; private int width; public Rectangle(int height, int width) { this.height = height; this.width = width; } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; Font f = new Font("Serif", Font.BOLD, 18); g2.setFont(f); int centerX = getWidth()/2; int centerY = getHeight()/2; g2.draw(new Rectangle2D.Double(centerX - width/2, centerY - height/2, width, height)); g2.draw(new Line2D.Double(centerX - width/2, centerY - height/2, centerX + width/2, centerY + height/2)); g2.draw(new Line2D.Double(centerX - width/2, centerY + height/2, centerX + width/2, centerY - height/2)); String text = "Rectangle"; FontRenderContext context = g2.getFontRenderContext(); double width = g2.getFont().getStringBounds(text, context).getWidth(); g2.drawString(text, centerX - (int) (width/2), centerY + height/2 + 18); } } Most of the points for this question will be given for eliminating redundancy, but some points will be given based on the ability to extend your Picture class without modifying it. For example, it should be possible to create other picture subclasses (e.g., a triangle, a diamond, a spiral) without modifying the Picture class itself. Include the definitions of Picture, Circle and Rectangle below. You do not have to copy all of the code if you give a clear description of what goes where. 2. Layout managers, 30 points. You are to write code that structures the layout managers for a JFrame. This particular JFrame is divided in half with an upper part and a lower part. The upper part is further divided in half. In the upper left are a pair of buttons and a panel that contains a clock. In the upper-right is panel that contains a live image of the bridge of the Enterprise (from Star Trek). The two buttons should appear stacked one on top of the other against a cyan background. The buttons should have their preferred height and width, so that any additional horizontal space goes to the clock panel. In the lower half of the frame is a panel that contains a short range scan with a button on top for quitting the application. Notice that the quit button has its preferred height but fills the width of the frame. Further notice that there is a black line separating the top and bottom halves of the frame and in the upper half there is a black line separating the left and right halves. These black lines should be 5 pixels wide. If the frame is made larger, additional space goes to the clock, the image of the bridge and the short range scan. Below is a snapshot of how the frame should look.
Assume that the following variables have been defined: clock the panel that draws the clock bridge the panel that shows the image of the bridge shortScan the panel that draws the short range scan save the save button rescan the rescan button quit the quit button You are to write code that would be included in the frame's constructor to lay out these components properly. Note that you only have to do the layout. You don't have to create the objects, attach listeners or otherwise solve the overall problem. The only objects you should create are the layout containers and any layout managers. You should set background colors appropriately. You may assume the frame class has the following general structure: public class TrekFrame { private JFrame frame; // other fields (not shown) public TrekFrame() { frame = new JFrame(); frame.setSize(450, 500); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setTitle("cse190L scan monitor"); // code to set up other fields (not shown) // your code here } public void start() { frame.setVisible(true); } // other methods (not shown) } You may define private methods that would be called by the code you are adding to the constructor. 3. Classes, 30 points. Define a class called ElapsedTime for storing elapsed times. It should have the following constructor: public ElapsedTime(int hours, int minutes, int seconds) // post: constructs a date object for given hours, minutes, seconds The constructor should throw an IllegalArgumentException if any of the thre parameters is negative. It should be possible to add the value of a second time object using the following method: public void add(ElapsedTime t) // post: adds the given time to this time In doing so, it's possible that the minutes or seconds can "overflow". For example, if one time has 32 seconds and the other has 47, the sum is 79, but that should be reported as 1 minute and 19 seconds. So your class has to take care of seconds overflowing into minutes and minutes overflowing into hours. Hours can be any value. You need to handle the overflow problem even if it happens in the constructor (i.e., if someone constructs an object with something like 84 seconds, you have to change that to 24 seconds and increment the minutes by 1). You should include methods getHours(), getMinutes() and getSeconds() to obtain the individual components. The getMinutes() and getSeconds() methods should always return integers in the range of 0 to 59. You should also include a toString method that converts it to the familiar notation of hours:minutes:seconds, again with minutes and seconds in the range of 0 to 59. Minutes and seconds should always be reported as two characters. For example, you'd report "3:05:07" to indicate 3 hours, 5 minutes and 7 seconds rather than "3:5:7". Finally, your class should implement the Comparable interface, ordering the times from shortest to longest, and should override the equals and hashCode methods. 4. Programming, 10 points. Suppose that a ListItem class has been defined as follows: class ListItem { public String name; public boolean hidden; public ListItem(String name) { this.name = name; hidden = false; } public void setHidden(boolean hidden) { this.hidden = hidden; } public boolean isHidden() { return hidden; } public String getName() { return name; } } This defines a list item that can store a single string and that can be set to be hidden (true or false). Notice that by default, list items are not hidden. You are to define a class List that includes the following public methods: public List(String name) constructs an empty list with given name public void add(<some type> item) adds given item to the end of the list public int length() returns the current length (ignoring any hidden values) public int size() returns the current length (including all values) public <some type> get(int index) returns the item at the given index public void setHidden(boolean hidden) sets whether or not this list is hidden public boolean isHidden() returns true if this list is hidden, otherwise returns false public String getName() returns the name of this list Part of this question involves design. The descriptions above mention a type "<some type>". You are to decide what this type should be. Whatever you chose, it has to be possible for a list to contain a combination of list items and lists. In other words, the add method above could be called with a parameter either of type List or of type ListElement. This allows you to nest lists as deeply as you want to (e.g., a list of lists of list items). The size and get methods don't pay attention to whether or not values are hidden, but in computing the length of a list, you are to ignore any hidden elements. For example, if a list stores 7 values, 2 of which are currently hidden, then the length should be reported as 5 even though the size would be reported as 7. Half of the points for this question will be awarded on the basis of your ability to structure your solution in such a way that there is minimal code duplication. This may lead you to want to modify the ListElement class. For example, you might want it to have a different inheritance relationship or you might want to move some of its methods or fields elsewhere. Briefly describe below any changes you want to make to the ListElement class and provide your solution to class List below.
Stuart Reges
Last modified: Sun Jun 3 19:25:01 PDT 2007