GUI
[Framework practical 6 of 7]


Now lets add some MenuItems.

Menus are heirarchically structured, starting with a MenuBar (at the top of the application), which may have multiple drop-down Menus, each of which can then have multiple MenuItems.

Here's the code for a menu with a "Open..." MenuItem:

   MenuBar menuBar = new MenuBar();
   Menu fileMenu = new Menu("File");
   menuBar.add(fileMenu);
   MenuItem openMenuItem = new MenuItem("Open...");
   fileMenu.add(openMenuItem);
   setMenuBar(menuBar);

Hopefully this should make some sense. Note that we don't use the Frame's add() method to add the MenuBar to the GUI: there is a special method to set the MenuBar.

Add this code to your Analyst constructor code, between the code setting the size and the code setting the frame visible.


Next we need to make ourselves a listener for the menu. We may as well make the Analyst class the listener as well as the Frame. To do this, we need to implement ActionListener, as it says in the MenuItem docs.

Change the class declaration so that after it says it extends the Frame class, it also says it implements ActionListener (there is nothing to stop classes listening to objects inside themselves, or, indeed, extended GUI components acting as their own listeners).

   public class Analyst extends Frame implements ActionListener {


Add the following code inside the Analyst class, but outside the constructor - this is another method for this class and shouldn't go inside any existing methods, just the class block.

   public void actionPerformed(ActionEvent e) {
      MenuItem clickedMenuItem = (MenuItem)e.getSource();
      if (clickedMenuItem.getLabel().equals("Open...")) {
         store.setData(io.readData());
      }
   }

Note the use of the .equals method to compare two Strings: as we saw in the second set of lectures this compares the words stored inside a String variable, not the String variable as an object, which == does. So:

String a = "hello";
String b = "hello";
String c = a;

a.equals(b) // true
a == b // false
a == c // true

Using == to try and compare the content of two Strings is a classic mistake, and a really hard bug to spot.

Also note the combining of results: the JVM would work out the result of clickedMenuItem.getLabel() first, get that String, and then call this String's .equals method.

If you compile the code above, you'll notice there's a problem - we got rid of both the IO class object "io" and Storage class object "store" at the start of the practical. Moreover, even if we hadn't got rid of them, they'd still be in the constructor, and not in this method, so they'd be out of scope here (we could put them in this method, but then they'd only exist for the milliseconds it took for this method to run, before being binned, and we want to keep the data). So, where should be put them that all the methods in this class can use them and where they exist as long as the Analyst class is running?

Have a think about this, then go on to Part Three, for the answer.