CM10228 / Programming Ib:   Lecture 12a


Intro to Graphical User Interfaces


-I  Testing, Scaling & Iterative Design 2

  1. What is a reasonable plan for testing the AI?
    1. Hints:
      1. title of this subsection
      2. the answer is NOT doing all three steps above & *then* testing.
  2. Everyone should be able to get good marks on the test plan!  Just think about it first!
    1. "Test plan" is really the design plan as well.
      1. Figure out how you are going to approach the problem design.
      2. Figure out how you know you are done with one stage and should move to the next test.
      3. May also do this hierarchichally, on sub-problems.
        1. Won't have room to document these details in the CW3 submission, just the highest level.
    2. Same about commenting.  Where do comments go?
      1. every method & class gets commented
      2. any tricky algorithms get commented
      3. commenting too much can obfuscate your code as badly as commenting too little
    3. Still, there is also the idea of satisficing
      1. Need to decide what is worth your time.
      2. Want to use anytime algorithms in your life as much as possible
        1. have some solution available whenever the time runs out,
        2. the more time you get the better

I. GUI: Graphical User Interface

  1. Most languages now have a way to build window applications.
  2. Even older languages like basic & lisp.
  3. One of the main reasons people use Java is because it provides good window widgets which are also platform independent.
    1. There are now other very good ways to do this, e.g. python.
    2. We'll talk more about the whole platform-independent thing & Java's history in the IP lecture.
  4. There are two main types of windowing widgets in Java: AWT & Swing.
    1. Most people use Swing now, so that's what we'll cover in this lecture.
    2. AWT was the original though, & you'll notice some things still come from its classes.
    3. Again, more on AWT in the history lecture (after break).
  5. Modern windowing systems have many things in common:
    1. Basic widgets: buttons, menus, sliders.
    2. Certain organizational things: frames, windows, containers, panels.
    3. Once you've learned about these things, you'll see them in all the applications you use.
    4. Once you've learned the concepts, it's pretty easy to learn to do it in other languages.
  6. Languages or libraries for languages will often have some special widgets too.
  7. If you want something that you've seen in another language, you can often find it implemented for any popular language via an Internet search.

III. Basic Ontologies

  1. Old standard:  Model, View, Controller.
    1. Model is essentially the underlying data & functionality.  What do you have and what can it do?
    2. View is the way it looks on the screen.  You might have different views for different people:
      1. different windowing systems,
      2. different preferences, `skins'.
      3. different permissions / options level
        1. e.g. Novice vs. Advanced options on browser
        2. all the same options are there in the code / model, but which ones you get check boxes for depend on how much you want to know, how much complexity you want to deal with.
        3. Can be used for security, e.g. should a customer see / know about options only a service provider can set?
    3. Controller is how you connect these two together:
      1. e.g. what happens when you mouse over a button?  when you push it?
      2. something needs to generate an event, and something needs to respond to that event.
  2. In Java, you must inherit from / extend a class that is essentially the main window, and implement a Listener.
    1. Widgets are also classes, instances of them become members of your new class.
    2. Listeners are for "listening for" events that occur in a program.
      1. Very much like catching an unforced exception.
      2. Can always ignore events, but users will be annoyed!
      3. Can do the listening with an anonymous inner class instead of a full implementation.
        1. Remember we talked about these in lecture 9 (well, you just saw it yesterday...)
        2. Demonstrated further below.

III. Example With & Without Inner Classes

  1. Notes for the lecture:
    1. Write on board with  big spaces for the  inner class version.
    2. Only write the code, explain the comments.
    3. Just mention the imports, don't list.
  2. Here's the code...

    import java.awt.Container;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;

    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;

    /**
    * @author joanna
    *
    * Window demo, taken from Johnston04 (java prog today)
    *
    */
    public class BangPopAp extends JFrame implements ActionListener {

    // these are all the widgets our inane ap will use
    JButton bangButton = new JButton ("Bang");
    JButton popButton = new JButton ("Pop");

    // now we set everything up in the constructor...
    public BangPopAp() {
    // set the title bar for the window
    this.setTitle("Bangs and Pops!");

    // Frames come with their main container. This just adds a reference
    // so we can refer to it more easily.
    Container canvas = getContentPane();
    // the layout determines where things will go when we add them.
    canvas.setLayout (new GridLayout(2,1));

    // here we add the buttons
    canvas.add(bangButton);
    canvas.add(popButton);

    // we have to tell the buttons what's going to listen to them.
    // Doing this is sometimes called "registering". We can use the instance
    // `this' because we are implementing an ActionListener (see below).
    // Once we've registered, when an event happens to one of the buttons,
    // it will call its listener's .actionPerformed.
    bangButton.addActionListener(this); // Leave lots of space around these for inner classes!!
    popButton.addActionListener(this);

    // The below two methods are both inherited from JFrame.
    // The first sets the size the window will be when it appears.
    // Generally want a value so all your widgets look reasonable from start.
    this.setSize(250,150);
    // Everything would pretty much work now, but if we didn't do show()
    // no one could see it!
    this.show();

    }

    // this is the one thing we have to do to implement ActionListener.
    // We have to define method "actionPerformed". This just looks to see which
    // widget called it (buttons only have one action!)
    public void actionPerformed(ActionEvent e) {
    if (e.getSource()==bangButton) {
    JOptionPane.showMessageDialog(this, "Bang!");
    } else if (e.getSource()== popButton) {
    JOptionPane.showMessageDialog(this, "Pop!");
    }
    }

    // now all we do to start the ball rolling is make an instance...
    public static void main(String[] args) {
    BangPopAp theApp = new BangPopAp();
    // except we also need to say what to do when the frame is closed!
    // if we didn't have this line, the program would keep running even
    // after the window was gone (that would be bad...)
    theApp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }


    } // class

  3. Next Lecture I'll tell you about a bunch of different possible components & layouts.
  4. There are a lot less options to replace JFrame with
    1. Applets (see history & IP lecture)
    2. JWindow
      1. simpler superclass of JFrame
      2. pretty much only used for splash screens.
  5. This lecture I'll tell you about more different listeners.
  6. But first, let's have a look at what we have to change to do this with inner classes:
    import java.awt.Container;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;

    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;

    /**
    * @author joanna
    *
    * GUI w/ inner classes demo, taken from Johnston04 (java prog today)
    *
    */
    public class BangPopInnerAp extends JFrame { // implements ActionListener {

    // these are all the widgets our inane ap will use
    JButton bangButton = new JButton ("Bang");
    JButton popButton = new JButton ("Pop");

    // now we set everything up in the constructor...
    public BangPopInnerAp() {
    // set the title bar for the window
    this.setTitle("Bangs and Pops!");

    // Frames come with their main container. This just adds a reference
    // so we can refer to it more easily.
    Container canvas = getContentPane();
    // the layout determines where things will go when we add them.
    canvas.setLayout (new GridLayout(2,1));

    // here we add the buttons
    canvas.add(bangButton);
    canvas.add(popButton);

    //Here's where the inner classes come in -- we can't use `this' anymore.
    // since we aren't extending the listener.
    bangButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent event) {
    JOptionPane.showMessageDialog(null, "Bang!");
    }
    });

    popButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent event) {
    JOptionPane.showMessageDialog(null, "Pop!");
    }
    });


    // The below two methods are both inherited from JFrame.
    // The first sets the size the window will be when it appears.
    // Generally want a value so all your widgets look reasonable from start.
    this.setSize(250,150);
    // Everything would pretty much work now, but if we didn't do show()
    // no one could see it!
    this.show();

    }

    /* this goes away now we're using inner classes
    public void actionPerformed(ActionEvent e) {
    if (e.getSource()==bangButton) {
    JOptionPane.showMessageDialog(this, "Bang!");
    } else if (e.getSource()== popButton) {
    JOptionPane.showMessageDialog(this, "Pop!");
    }
    }
    */
    // now all we do to start the ball rolling is make an instance...
    public static void main(String[] args) {
    BangPopAp theApp = new BangPopAp();
    // except we also need to say what to do when the frame is closed!
    // if we didn't have this line, the program would keep running even
    // after the window was gone (that would be bad...)
    theApp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }


    } // class

  7. Duplicates some code for each widget, but,
    1. Eliminates need for logic in the actionPerformed method to determine which object got called,
    2. Localizes a little better --- code pertaining to widget objects less spread out.
  8. Remember, you can implement multiple interfaces, may want more than one kind of listener!

IV. Listeners

  1. There are tons of kinds of EventListeners
    1. ActionListener -- actionPerformed (button press, slider moved, etc)
    2. FocusListener -- focusGained (FocusEvent e), focusLost.
      1. Focus is basically where you can type, as in "focus of attention".
      2. You can also make a widget request the focus (like Google does in its search window) JComponent.requestFocus()
    3. MouseListener (MouseEvent e)
  2.  void mouseClicked(MouseEvent e)
              Invoked when the mouse button has been clicked (pressed and released) on a component.
     void mouseEntered(MouseEvent e)
              Invoked when the mouse enters a component.
     void mouseExited(MouseEvent e)
              Invoked when the mouse exits a component.
     void mousePressed(MouseEvent e)
              Invoked when a mouse button has been pressed on a component.
     void mouseReleased(MouseEvent e)
              Invoked when a mouse button has been released on a component.
    1. MouseMotionListener
       void mouseDragged(MouseEvent e)
                Invoked when a mouse button is pressed on a component and then dragged.
       void mouseMoved(MouseEvent e)
                Invoked when the mouse cursor has been moved onto a component but no buttons have been pushed.
  3. Also table, menu & hyperlink listeners, many others.

V. Summary

  1. Introduced GUIs
  2. You should play with them & look at the documentation.

page author: Joanna Bryson
  6 March 2014