Source: Horstmann's lab 12

Graphical User Interfaces

1.

P1. Buttons

All problems in this lab are based on the HelloTest program.
HelloTest.java
HelloFrame.java
HelloPanel.java

In this problem, you need to add two buttons to the bottom of the frame, like this:



Follow these steps:

   1. Make two instance variables of the class JButton:
   
      private JButton smallerButton;
      private JButton largerButton;

   2. In the frame constructor, initialize the variables with JButton objects:
      
      smallerButton = new JButton("Smaller");
      largerButton = new JButton("Larger");

   3. Place the buttons into a panel:

      JPanel southPanel = new JPanel();
      southPanel.add(smallerButton); southPanel.add(largerButton);

   4. Add that panel to the "South" end of the content pane:

      contentPane.add(southPanel, "South");

Make these changes in your program. Run the program to confirm that the buttons appear.

What happens when you click the buttons? Why?



2.

Next, you need to connect the buttons to actions. For each button, carry out these steps:

   1. Create a class that implements the ActionListener interface and override the actionPerformed method.
   2. Make an object of that class.
   3. Install that object as the action listener of the button.

Perform these steps one at a time.

When the "Larger" button is clicked, we want to increase the font size by 25 percent. When the "Smaller" button is clicked, we want to decrease it. To avoid integer rounding errors, keep a floating-point variable fontSizeFactor that is initialized with 1. Clicking on the buttons multiplies by 1.25 or 0.8 (because 0.8 = 1/ 1.25).

Here is an appropriate action listener for the "Larger" button.

class LargerFontAction implements ActionListener
{
  public void actionPerformed(ActionEvent event)
  {
     fontSizeFactor = 1.25 * fontSizeFactor;
     panel.setMessageSize((int)(fontSizeFactor * DEFAULT_SIZE));
  }
}

This class is an inner class of the frame class since the actionPerformed method needs to access the panel and fontSizeFactor instance variables of the frame class.

To connect it to the "Larger" button, you need to create an object of this class and set it as an action listener of the button. Place the following instructions into the frame constructor:

LargerFontAction largerAction = new LargerFontAction(); largerButton.addActionListener(largerAction);

Add the code, compile the program, and run it.

Click on both buttons several times. What happens?



3.

Repeat the steps above for the "Smaller" button. Make an action listener class and add an instance of that class as an action listener of the smallerButton. Run your program. Both buttons should work.

What is the complete source code for your frame constructor?



4.

In this program, the two button actions are very closely related. Both multiply the fontSizeFactor by a number. You can reduce the number of classes by recognizing that commonality.

Make a helper function

public ActionListener makeScaleAction(final double scaleFactor)
{
  class ScaleAction implements ActionListener
  {
     public void actionPerformed(ActionEvent event)
     {
        . . .
     }
  }
  return . . .;
}

Then you can simply add the return value of makeScaleAction(1.25) as the action listener of the largerButton, and a makeScaleAction(0.8) as the action listener of the smallerButton.

Try out this enhancement. Remove the LargerFontAction and SmallerFontAction classes and replace them with the makeScaleAction values.

What is the complete source code for your frame class now?



5.

P2. Menus

In this program, we will use a menu instead of a set of buttons to increase and decrease the font size.



As with buttons, you need to solve two unrelated issues:

   How to place the menu items
   How to connect actions to the menu items.

In Java, there is a three-level hierarchy for menus.

   1. A menu bar is attached to a window.
   2. The menu bar contains menus, rectangular panels with menu strings inside them.
   3. Menus contain submenus and menu items.

Only menu items have actions associated with them.

Here are the instructions to build the menu for this program.

JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);

JMenu fontMenu = new JMenu("Font");
menuBar.add(fontMenu);

JMenuItem largerItem = new JMenuItem("Larger");
fontMenu.add(largerItem);

JMenuItem smallerItem = new JMenuItem("Smaller");
fontMenu.add(smallerItem);

Start again with the HelloTest program.

Place these instructions into the constructor of the frame class of the HelloTest program.

Run your program and check that the menu works. What happens when you select a menu item?



6.

Next, you need to attach actions to the menu items. This process is identical to attaching actions to buttons. Simply reuse the makeScaleAction method from the preceding exercise.

Attach the actions to the two menu items and run your program. Check that selecting the menu items respectively increases and decreases the font size.

What is the complete source code for your frame class now?



7.

P3. Combo Boxes

In this exercise, you will see how to offer a user a selection among multiple choices. You can place all choices into a combo box.



To build such a combo box, you add items to it:

comboBox = new JComboBox();
comboBox.addItem("Small");
comboBox.addItem("Medium");
comboBox.addItem("Large");
comboBox.addItem("Extra Large");

Then place the combo box in the south end of the content pane.

contentPane.add(comboBox, "South");

Try it out. Run the program and compare it against the figure.

The program looks different. Why?



8.

The border layout grows all items to their maximum size. To avoid this, enclose the combo box inside a panel, even though it is a single item.

JPanel southPanel = new JPanel();
southPanel.add(comboBox);
contentPane.add(southPanel, "South");

Try it out. Add the combo box to the frame of the HelloTest program. Compile and run the program. Pull down the item list of the combo box to see the items.

What happens if you select one of the items?



9.

To activate the combo box, you need to attach an action listener. The actionPerformed method needs to determine which item the user selected.

class ComboAction implements ActionListener
{
  public void actionPerformed(ActionEvent event)
  {
     String item = (String)comboBox.getSelectedItem();
     . . .
  }
}

You need to cast the return value of the getSelectedItem method to a String because it is possible to put other objects, such as icons, into a combo box.

Now you simply set the correct font size, depending on the item string.

int messageSize = DEFAULT_SIZE;
if (item.equals("Small")) { messageSize = SMALL_SIZE; }
else if (item.equals("Medium")) { messageSize = MEDIUM_SIZE; }
else if (item.equals("Large")) { messageSize = LARGE_SIZE; }
else if (item.equals("Extra Large")) { messageSize = EXTRA_LARGE_SIZE; } panel.setMessageSize(messageSize);

Define the size constants as follows:

public static final int SMALL_SIZE = 12;
public static final int MEDIUM_SIZE = 18;
public static final int LARGE_SIZE = 24;
public static final int EXTRA_LARGE_SIZE = 36;

Add the combo action listener and try out your program. When you select an item from the combo box, the message should be displayed in the appropriate size.

What is the complete source code for your frame constructor?



10.

P4. Radio Buttons and Check Boxes

Radio buttons are another to offer the user a selection among multiple alternatives.



These buttons are called radio buttons because they work like the channel buttons on a radio. When you select a radio button, the previously selected radio button is turned off.

However, radio buttons take up more screen "real estate" than combo boxes and therefore are best used when you need to offer users only a small selection.

Here are the instructions to construct two radio buttons:

helloButton = new JRadioButton("Hello");
goodbyeButton = new JRadioButton("Goodbye");

To get the "radio button" effect, where all other buttons are turned off when one of the buttons is clicked, you need to place the buttons in a button group:

ButtonGroup group = new ButtonGroup();
group.add(helloButton);
group.add(goodbyeButton);

Finally, you want to turn the first button on:

helloButton.setSelected(true);

The button group is a logical grouping of the buttons. You still need to physically lay out the buttons on the screen:

JPanel southPanel = new JPanel();
southPanel.add(helloButton);
southPanel.add(goodbyeButton);
contentPane.add(southPanel, "South");

Add the two radio buttons to the frame of the HelloTest program. Run the program. What happens when you click the radio buttons?



11.

Now change the message text when the user clicks a radio button. To assemble the correct text, simply check which button is currently selected.

class MessageAction implements ActionListener
{  
  public void actionPerformed(ActionEvent event)
  {
     String message = "";
     if (helloButton.isSelected()) message = "Hello";
     else if (goodbyeButton.isSelected()) message = "Goodbye";
     message += ", World!";
     panel.setMessageText(message);
  }
}

Note that you can attach the same action object to both buttons.

Add the action listener and attach it to the radio buttons. Run the program. Observe how clicking the buttons changes the message text.

What is the complete source code for your frame constructor?



12.

Check boxes are used to allow users to select a single logical alternative, typically of the form "do X" or "do nothing". Here, a check box is used to allow the user to specify whether the word "cruel" should be added to the message text:



Follow these steps to add the check box to the program.

   1. Construct the check box.

      cruelCheckBox = new JCheckBox("Cruel");

   2. Attach the same action listener to the check box and the radio buttons.

      cruelCheckBox.addActionListener(action);

   3. Add the check box to the south panel.

      southPanel.add(cruelCheckBox);

   4. In the actionPerformed method of the MessageAction class, check

      if (cruelCheckBox.isSelected()) . . .

Run the program. Observe how clicking the check box changes the message text.

What is the complete source code for your frame constructor now?