// CS111 Lab 13 Spring 2000 import java.awt.*; // use graphics import java.applet.*; // use applet public class LOLApplet extends Applet { // hack for being able to refer to IntList and IntListList methods // by abbreviations IL and ILL respectively private static IntListOps IL; private static IntListListOps ILL; private static String[] methodNames = {"mapSum", "mapMapDouble", "subsequences", "combination", "mapMapPrepend"}; // Instance variables private IntList ns = IL.empty(); private IntListList nss = ILL.empty(); // Graphical elements private TextField numberField; private Canvas c; private Label nsLabel, nssLabel; /******************** * GUI Layout ********************/ // The init method sets up the layout for the applet. // The init method is a standard applet method whose contract is // public void init(); // For a clean design, use methods to create the parts of the layout. public void init () { this.setLayout(new BorderLayout()); // sets the overall layout for applet this.add("North", makeListPanel()); this.add("Center", makeCanvas()); this.add("East", makeMethodButtonPanel()); this.add("South", makeListLabelPanel()); } // Use private methods for the other methods written to generate the layout. // This method creates the top panel of the applet. // The top panel is a GridLayout with 2 rows and 2 columns. // Elements in a grid layout are added left-to-right, top-to-bottom. // Three of the sections are very similar -- they are buttons in panels. // Any time there are common GUI elements, make a method to create that element. // That way it is easy to make style changes. // makeListButtonPanel creates the button in the panel // Also notice that all four buttons are similar in style. // makeListButton creates those buttons. // For the second space in the grid layout (left-to-right, top-to-bottom), // there is more than one element in the grid cell. // Since only one component can be placed in each grid cell, // There must be a Panel there with components in the Panel. // The Panel component is used for organizing components in the GUI. // To keep this method easy to read, we also write a method to create that // second panel -- makeIntListPanel // Notice that we can set the background and foreground color of any // GUI component via the methods setBackground and setForeground. private Panel makeListPanel () { Panel p = new Panel(); p.setBackground(Color.yellow); p.setLayout(new GridLayout(2,2)); p.add(makeListButtonPanel("New IntList")); p.add(makeIntListPanel()); p.add(makeListButtonPanel("New IntListList")); p.add(makeListButtonPanel("Prepend IntList to IntListList")); return p; } // This method creates a Panel with a ListButton in it. // ListButton is just the name we have given to the buttons in the top Panel // because they all have the same style. private Panel makeListButtonPanel (String label) { Panel p = new Panel(); p.add(makeListButton(label)); return p; } // This method creates a Button in the style in the top Panel of our applet. // Since the style information is in this method, we can easily change the // colors or fonts of the Button. Notice that the foreground color of a component // is the color the label is rendered in. The background color defaults to the // background color of its container (the Panel it is in) unless we specify // something in particular. private Button makeListButton (String label) { Button b = new Button(label); b.setBackground(Color.red); b.setForeground(Color.black); return b; } // This method creates the second Panel in the GridLayout of the top Panel. // We use the default FlowLayout of Panels, so there is no need to specify a layout. // In this Panel we have a TextField. Since the TextField is something that we // want to be able to read and modify later, we need to store it in an instance // variable. At the top of the class, we have declared the following instance variable: // private TextField numberField; // In this method, we initialize the numberField instance variable. // The TextField constructor has many options. Below, we specify the desired size // of the TextField (in characters it can display). There are also constructors which // allow us to set the initial text in the TextField. See the API for details. // Again, we demonstrate that we can set the color of any GUI component. // Here, we set the background color of the TextField. private Panel makeIntListPanel () { Panel p = new Panel(); numberField = new TextField(3); // initialize the instance variable numberField.setBackground(Color.cyan); p.add(numberField); p.add(makeListButton("Prepend to IntList")); return p; } // This method creates the Canvas in the center of our applet. // A Canvas is a GUI component which we can "draw" on. // While we could also draw over Buttons and TextFields, we generally don't want to. // Since we will need to use the Canvas later (in order to be able to draw on it), // we need to store the Canvas in an instance variable. At the top of the class, // we have declared the following instance variable: // private Canvas c; // In this method, we initialize the c instance variable. private Canvas makeCanvas () { c = new Canvas(); // initialize the instance variable return c; } // This method creates the Panel in the East side of our applet. // The layout is a GridLayout with 5 rows and 1 column. // We have five buttons, all the same style, so we capture the pattern // in a method, makeMethodButton. // While we could create each Button and add it to our panel like so: // p.add(makeMethodButton("methodName")); // here we demonstrate how to place all the names of the Buttons // into a class constant. At the top of the class we have the following declaration: // private static String[] methodNames = {"mapSum", "mapMapDouble", // "subsequences", "combination", "mapMapPrepend"}; // In this method, we loop through the methodNames String array // and create a Button for each name. private Panel makeMethodButtonPanel () { Panel p = new Panel(); p.setLayout(new GridLayout(5,1)); for (int i=0; i<5; i++) { p.add(makeMethodButton(methodNames[i])); } return p; } // This method creates the Buttons for the method names. // Again, we are capturing similar styles in one location so they are // easy to change. In this Button, we set the background and foreground // colors as well as change the font of the label on the Button. // For more about Fonts, read the notes in Lab 11, Task 2 or the Java API. private Button makeMethodButton (String label) { Button b = new Button(label); b.setBackground(Color.blue); b.setForeground(Color.white); b.setFont(new Font("Times", Font.BOLD, 14)); return b; } // This method makes the Panel at the bottom of the applet. // This Panel has a GridLayout with 2 rows and 1 column. // There is one Label in each grid cell. // Since the Labels are components that we will want to change later, // we need to create instance variables to hold them. // We want one label to show the current IntList, and one label for the IntListList. // At the top of the file, we have the following instance variables declared: // -- instance variables to hold the current IntList and IntListList // notice that the variables are initialized at the point of declaration // just so we don't forget to do so later // private IntList ns = IL.empty(); // private IntListList nss = ILL.empty(); // -- instance variables to hold the Labels which display the lists // private Label nsLabel, nssLabel; private Panel makeListLabelPanel () { Panel p = new Panel(); p.setBackground(Color.green); p.setLayout(new GridLayout(2,1)); nsLabel = makeListLabel("IntList: "+ns.toString()); p.add(nsLabel); nssLabel = makeListLabel("IntListList: "+nss.toString()); p.add(nssLabel); return p; } // This method creates the Labels in the bottom Panel of the applet. // We write a method to create the Labels so that it will be easy // to change style information like the foreground color, font, etc. private Label makeListLabel (String text) { Label l = new Label(text); l.setFont(new Font("Courier", Font.BOLD, 14)); return l; } /******************** * GUI Behavior ********************/ // The action method is another standard applet method. // The action method is what gets called when a user hits a button // or selects something in a choice (drop-down options). // The skeleton for an action method is // public boolean action (Event evt, Object arg); // The action method returns true or false depending on if it // successfully handled the action or not. // In general, we write the action method as a series of if-else // statements stating which actions we want to serve. // At the very end of the method, we pass control of all other // events to our superclass (the Applet itself) so that the Applet // will respond properly to user actions. We do this via the following // else clause: // } else { // return super.action(evt, arg); // } // At the end of the method, we return true to indicate that we // have sucessfully handled the actions that we've specified. // We could also have added "return true" inside every if-else // clause, but that is tedious which is why we place it at the end // of the method, outside of the if-else statement. // The style of coding we recommend for the action method is // to check for each Button and "dispatch" to another method // for the actual action which occurs when the Button gets pressed. // Coding in this way makes the action method much easier to read // and understand. public boolean action (Event evt, Object arg) { // Can test for a button press using one of two techniques: // (1) (evt.target == ) // (2) (arg.equals()) // Here, we must use approach 2 since we chose not to store buttons in instance variables. if (arg.equals("New IntList")) { // Always use .equals (never ==) to compare strings. newIntListAction(); } else if (arg.equals("New IntListList")) { newIntListListAction(); } else if (arg.equals("Prepend to IntList")) { prependToIntListAction(); } else if (arg.equals("Prepend IntList to IntListList")) { prependToIntListListAction(); } else if (arg.equals("mapSum")) { mapSumAction(); } else if (arg.equals("mapMapDouble")) { mapMapDoubleAction(); } else if (arg.equals("subsequences")) { subsequencesAction(); } else if (arg.equals("combination")) { combinationAction(); } else if (arg.equals("mapMapPrepend")) { mapMapPrependAction(); } else { // Let the superclass handle the message. return super.action(evt, arg); } return true; // Indicate that we handled the action. } // Use private methods for the other methods written to implement the behavior of the applet. // This method implements what should happen when the "New IntList" Button is pressed. private void newIntListAction () { ns = IL.empty(); // set our instance variable to an empty IntList numberField.setText(""); // clear the TextField updateIntListLabel(); // update the Label which displays the IntList } // This method updates the IntList Label to reflect what the current IntList is. // We write a method to do this because it will be used in many places. // Notice that the setText method is used to set the string displayed for // Labels and TextFields (used above). private void updateIntListLabel () { nsLabel.setText("IntList: "+ns.toString()); } // This method implements what should happen when the "New IntListList" Button is pressed. private void newIntListListAction () { nss = ILL.empty(); // set our instance variable to an empty IntListList updateIntListListLabel(); // update the Label which displays the IntListList } // This method updates the IntListList Label to reflect what the current IntListList is. private void updateIntListListLabel () { nssLabel.setText("IntListList: "+nss.toString()); } // This method implements what should happen when the "Prepend to IntList" Button is pressed. // getText is used for reading TextFields. getText returns a String // In order to convert a String to an integer, we use the method Integer.parseInt(String) // We do not do any error checking here for if the field is empty or has non-integers. private void prependToIntListAction () { int number = Integer.parseInt(numberField.getText()); // get the number ns = IL.prepend(number, ns); // prepend it to our IntList numberField.setText(""); // clear the TextField updateIntListLabel(); // update the Label which displays the IntList } // This method implements what should happen when the "Prepend IntList to IntListList" Button is pressed. private void prependToIntListListAction () { nss = ILL.prepend(ns, nss); // prepend the IntList to the IntListList ns = IL.empty(); // set the IntList to be an empty IntList numberField.setText(""); // clear the TextField updateIntListLabel(); // update the Label which displays the IntList updateIntListListLabel(); // update the Label which displays the IntListList } // The following five methods are used when the method Buttons are pressed. // First, they construct a String which includes the name of the method and // the parameters of the method. // Then, they construct a String which is the answer from invoking the method // and then converting the answer to a String via the toString method. // Finally, they call the displayAnswer method (defined below) with the two // Strings created. private void mapSumAction () { String method = "mapSum("+nss.toString() + ")"; String answer = ListOfListsLab.mapSum(nss).toString(); displayAnswer(method, answer); } private void mapMapDoubleAction () { String method = "mapMapDouble("+nss.toString() + ")"; String answer = ListOfListsLab.mapMapDouble(nss).toString(); displayAnswer(method, answer); } private void subsequencesAction () { String method = "subsequences("+ns.toString() + ")"; String answer = ListOfListsLab.subsequences(ns).toString(); displayAnswer(method, answer); } private void combinationAction () { String method = "combination("+nss.toString() + ")"; String answer = ListOfListsLab.combination(nss).toString(); displayAnswer(method, answer); } private void mapMapPrependAction () { String method = "mapMapPrepend("+ns.toString() + "," + nss.toString() + ")"; String answer = ListOfListsLab.mapMapPrepend(ns,nss).toString(); displayAnswer(method, answer); } // This method displays the answer in the Canvas. // The first parameter is the name of the method and its parameters. // The second parameter is the answer from invoking the method. // We use the drawString method to draw Strings on the Canvas. // Note that drawString can only write a single line of text. // If the text is too long, it will bleed off the edge of the Canvas. // This is fine for now (the easiest thing to do). // Drawing on a Canvas always requires the following steps (illustrated in the method): // 1) get the Graphics context of the Canvas (so we can draw on it) -- use getGraphics() // 2) if we want to know the size of the Canvas, get that via the size() method // -- the size() method returns an instance of the Dimension class // -- the Dimension class has two public instance variables width and height // 3) use setColor() to set which Color we want to draw in // 4) draw on the Canvas // See the API on the Graphics class to see how to draw different shapes. // Below, we want to clear the Canvas before displaying the new answer // (or else we'd soon get a mess), so we use the clearRect method which // sets the Canvas's Color to its default color and draws a rectangle in // the area specified by its top-left corner and desired width and height. // Since we want to clear the entire Canvas, we give clearRect the Canvas's // width and height and start the rectangle at its top-left corner. private void displayAnswer (String method, String answer) { Graphics g = c.getGraphics(); // get Graphics context of Canvas Dimension d = c.size(); // get size of Canvas g.clearRect(0,0,d.width,d.height); // clear the Canvas g.setColor(Color.black); // set Color to black g.drawString(method, 10, 50); // draw method String at desired position g.setColor(Color.red); // set Color to red g.drawString(answer, 10, 100); // draw answer String at desired position } }