Package Title: Lab Questions
Course Title: Big Java 
Chapter Number: 18 Graphical User Interfaces

Question type: Essay

1.1) If you execute the code listed below, you should see a frame that contains a single red panel.  Modify the code so that it creates five additional panels of the same size, but with different colors: white, blue, green, yellow, and orange.  (View Sample.) Since we have not specified a layout manager for the main panel, the default FlowLayout manager is used to control the placement of panels.  What happens if you resize the frame to be narrower and longer? 

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.Color;
import java.awt.Dimension;

public class PanelRunner
{
   /**
      Creates and displays the application frame.
   */
   public static void main(String[] args) 
   {
      JFrame frame = new JFrame("Color Panels");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(1200, 1000);
      JPanel panel = new JPanel();
      panel.setPreferredSize(new Dimension(1200, 1000));
      JPanel subpanel1 = new JPanel();
      subpanel1.setBackground(Color.RED);
      subpanel1.setPreferredSize(new Dimension(200, 1000));
      panel.add(subpanel1);
      frame.add(panel);
      frame.setVisible(true);
   }
}

1.2) Create PanelRunner2 by modifying PanelRunner1.  Set the preferred panel sizes to 200 by 200 for each of the subpanels. Use the BorderLayout manager to control panel placement so that the subpanels are configured as below:

                              Red
       White      Blue     Green      Yellow
                              Orange

You will need to create another subpanel to hold the blue and green panels.  Try running the program and making the frame narrower.  Does the green panel disappear?  Why?  Fix the problem by using a GridLayout manager for the center panel.

1.3) Create PanelRunner3 by modifying PanelRunner2.  Set the preferred panel sizes to 200 by 200 for each of the subpanels.  Use the GridLayout manager to control panel placement so that the six subpanels are configured into three rows and two columns.  Add the subpanels so that the final arrangement appears as below:

                              Red      White
                              Blue      Green      
                              Yellow  Orange

What effect does narrowing or enlarging the frame have on the subpanels?

2) Create a class called ComboPanel that extends JPanel.  The class constructor should add three JComboBox objects to the panel and initialize each of them with Integer objects with values that range from 0 to 255.  Each JComboBox will allow the user to select an integer for the three components (red, green, and blue) that make up a Color object.  For example, invoking new Color(255, 215, 0) creates a yellowish color object. 

Create listener objects for each JComboBox that set the background color of the panel when the user selects an integer.  Use the current values supplied by the JComboBox objects to determine the background color.

Use the following code to test your class.

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JComboBox;

public class ComboPanelRunner
{
   /**      Creates and displays the application frame.   */   public static void main(String[] args) 
   {
      JFrame frame = new JFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(400, 500);
      ComboPanel cp = new ComboPanel();
      frame.add(cp);
      frame.setVisible(true);
   }
}

3)  Create a class called ColorFrame that extends JFrame.  Create a “Colors” menu with three menu items:  Red, Green, and Blue.  The ColorFrame class also contains a JPanel object that changes to the appropriate color when the user selects a menu item.  Use the following code as a demo class.

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JComboBox;

public class ColorPanelRunner
{
   /**      Creates and displays the application frame.   */   public static void main(String[] args) 
   {
      ColorFrame frame = new ColorFrame();
      frame.setSize(400, 400);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setVisible(true);
   }
}

4) (Optional)  Use the Java API to research the Swing class called JList.  Create a simple demo application that builds and displays a JList in a frame.

5.1) Problems 5.1- 5.4 in this lab are based on the HelloViewer program:

/** File HelloViewer.java */
import javax.swing.JFrame;
 
public class HelloViewer
{
   public static void main(String[] args)
   {
      JFrame frame = new HelloFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setTitle("HelloViewer");
      frame.setVisible(true);
   }
}

----------------------------
/** File HelloFrame.java */
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.BorderLayout;
import java.awt.Font;

public class HelloFrame extends JFrame
{   
   private String message;
   private JLabel label;
   
   private static int FRAME_WIDTH = 300;
   private static int FRAME_HEIGHT = 300;
   private static int DEFAULT_SIZE = 20;

   public HelloFrame()
   {
      message = "Hello, World!";
      label = new JLabel(message);
      label.setFont(new Font("Serif", Font.PLAIN, DEFAULT_SIZE));
      add(label, BorderLayout.CENTER);
      
      setSize(FRAME_WIDTH, FRAME_HEIGHT);
   }
}

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. Place the following two lines inside the constructor to 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 the south panel to the frame:

   add(southPanel, BorderLayout.SOUTH);

5. In the frame constructor, call the method createSouthPanel:

   createSouthPanel();

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

What happens when you click the buttons? Why?

What is the code of your HelloFrame class?

5.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.

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 instance variable fontSizeFactor that is initialized with 1. Clicking on the buttons multiplies by 1.25 or 0.8 (because 0.8 = 1/ 1.25).

   private double fontSizeFactor = 1;

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

      class LargerFontListener implements ActionListener
      {
         public void actionPerformed(ActionEvent event) 
         {
            fontSizeFactor = 1.25 * fontSizeFactor;
            label.setFont(new Font("Serif", Font.PLAIN,
                  (int) (DEFAULT_SIZE * fontSizeFactor)));
            label.repaint();
         } 
      }
 
This listener must be added to one of the buttons. As you can see, the code for setting up the buttons is getting quite complex. Introduce a new method createSouthPanel that contains all button initialization code. Place the listener class inside the createSouthPanel method, because the actionPerformed method needs to access the label and fontSizeFactor variables.

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:

ActionListener largerListener = new LargerFontListener();
largerButton.addActionListener(largerListener);

Add the code, compile the program, and run it. Don't add the code for the "Smaller" button yet.

Click on both buttons several times. What happens?

5.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 for the smallerButton. Run your program. Both buttons should work.

What is the code for the createSouthPanel method?

5.4) In the preceding program, the buttons were placed on the bottom of the frame, next to each other. Change your program so that they are placed on the right of the frame, one above the other.

What is the code for the HelloFrame class now?

6.1) (Optional) In this series of lab exercises, 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 HelloViewer program.

Create a method called createMenu, and place these instructions inside this method.

What is your createMenu method?

What happens when you select a menu item?

6.2) Next, you need to attach actions to the menu items. This process is identical to attaching actions to buttons. Simply reuse the code from the Lab 19.5.2.

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.1) 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:

final JComboBox 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 frame.
 
add(comboBox, BorderLayout.SOUTH); 

Add a createSouthPanel method and paste the lines indicated above inside the method. Try it out. Don't forget to call the createSouthPanel method from within the constructor. Run the program and compare it against the figure.

The program looks different. Why?

7.2) 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); 
add(southPanel, BorderLayout.SOUTH);
 
Try it out. Add the combo box to the frame of the HelloViewer 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?

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

class ComboListener 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; }
label.setFont(new Font("Serif", Font.PLAIN, messageSize));
label.repaint();

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 box 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 code for your createSouthPanel method?

8.1) Radio buttons are another way 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");
 
Lay out the buttons on the screen:

JPanel southPanel = new JPanel(); 
southPanel.add(helloButton); 
southPanel.add(goodbyeButton); 
add(southPanel, BorderLayout.SOUTH);
 
Add the two radio buttons to the frame of the HelloViewer program. Add a createSouthPanel method, just like you did in the previous problems. Run the program. What happens when you click the radio buttons? Why is this behavior wrong?

8.2) 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);
 
Now what happens when you click the buttons?

8.3) 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 MessageListener implements ActionListener 
{
   public void actionPerformed(ActionEvent event) 
   {
      String message = ""; 
      if (helloButton.isSelected()) { message = "Hello"; }
      else if (goodbyeButton.isSelected()) { message = "Goodbye"; }
      message = message + ", World!"; 
      label.setText(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 createSouthPanel method?

8.4) 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(listener);

3. Add the check box to the south panel.

   southPanel.add(cruelCheckBox);

4. In the actionPerformed method of the MessageListener class, add the action that should occur when the box is checked.

   if (cruelCheckBox.isSelected()) . . .

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

What is the complete source code for your createSouthPanel method now?

*** Omit the remaining activities ***

5.1 A user interface component such as a button can detect five types of mouse events. What are these events?

5.2.  This exercise focuses on "entered" and "exited" mouse events. Write a mouse listener class that prints "Mouse Entered" and "Mouse Exited" to System.out when the mouse has entered or exited the frame. Do nothing for the other three mouse event types. Call your class EnterExitListener. Remember that you need to implement the MouseListener interface.

Paste the code of your listener class below.

5.3. Write a MouseListenerDemo program that demonstrates your listener. You will need to add the listener to the frame using the addMouseListener method.

5.4.  The MouseListenerDemo program is a little dull. Make it more interesting. Rather than printing a message, change the background color of the frame. In the mouseEntered method, add the line

frame.getContentPane().setBackground(Color.BLUE);

and in the mouseExited method, add the line

frame.getContentPane().setBackground(Color.RED);

Make sure that your EnterExitListener is an inner class of the main method.

Compile and run your test program. When the mouse enters the frame, the background color should change to Blue. When the mouse leaves the frame, the background should turn red.

Enter the code for your MouseTester program here.

5.5.  Why must the EnterExitListener be an inner class?

Hint: If you are unsure, make EnterExitListener into a regular class, compile, and study the error message.

6.1 Write a component whose paintComponent method draws four lines:

	1. From the point p to the top left corner
	2. From the point p to the bottom left corner
	3. From the point p to the top right corner
	4. From the point p to the bottom right corner

Let p be the point with the coordinates (50, 100).

Call your component FourLineComponent.

Hint: Call getWidth() and getHeight() to get the x- and y-coordinates of the corner points.

If added to a frame and displayed, the component should look like this:

Enter the code for your component here.

6.2.  Now write a viewer program that creates a frame, adds the FourLineComponent to the frame and displays it. Call it FourLineComponentViewer.

6.3.  Now enhance the program so that the point p can be changed by a mouse click.

Add a method to the component that allows setting the point, so that it can be changed during the program execution. If you did not have x and y instance variables in the component, you will need to modify the paintComponent method too, so that the lines all have one end in this point.

Paste the code of your modified FourLineComponent class here.

6.4.  Write a MousePressListener class that implements the MouseListener interface. Its mousePressed method sets p to the point with the  x- and y-values of the mouse event.

Make sure that the mousePressed method calls the repaint method on the component, after changing p. You can use the getX and getY methods to find the position where the user clicked:

event.getX()

Add a MousePressListener as mouse listener to the viewer program.

Run your program. Now you should be able to click the mouse and have the four lines meet at the point where you just clicked.

Enter the code for your program here.

6.5.  Why is it important to call repaint in the mouse press listener? What would happen if you didn't call repaint?

Try it out. Comment out the call to repaint, recompile, and try your program again. What happens?