GUI I

From CompSciWiki
Jump to: navigation, search

Extra Labs: GUIs, Part I

In this lab, we'll learn the basics of designing GUIs to build nicer-looking windows for your Java applications. This will be followed in Part II by a more involved example using google maps.

Here's an example of a GUI window, with the names of the components labelled:

Swing.jpg

In this lab, we'll learn how to build a window with these components and have it execute our code.

Step 1: Building a basic Window

The basic structure of all our examples of GUIs will be built on the JFrame class. This involves two things that we typically don't do in COMP 1010 (but which may be familiar to you from previous computer science classes):

  1. using the extends keyword to tell Java that we are adding on to an existing class (in this case, JFrame).
  2. using the main method to call a constructor method. This is actually somewhat of a hack, but it saves us the hassle of having to write two different classes. (If you don't know what a constructor method is, don't worry. We will just tread it like a method in this lab.)

So we will use this basic framework for all our GUIs:

import javax.swing.*;

public class myGUI extends JFrame {
  public static void main (String[] args) { 
     new myGUI();
  }

  public myGUI() {
      // all the setup for the GUI will go here. 
  } 

}

In what follows, all our code will follow this basic setup, and we will only modify the code in the myGUI method (the constructor method). For our purposes, we can consider this the "main method" for our GUI.

The previous example is great, but if we run it, nothing actually happens. To get our example to do anything, we need to make our window visible. Let's change our myGUI method to actually have some code:

public myGUI() {
  setVisible(true);
}

When we run this code, a new window should pop up, with no actual content. This makes sense: we haven't added anything to our window yet. Let's do that.


Step 2: Adding components

When we used JOptionPane for input and output, we were only able to use what JOptionPane provided: one input box, OK/Cancel buttons, etc. But with JPanel, we can add buttons, labels and textfields to get as much or as little input and display as much or as little output as possible. These are called components, and Java provides lots of them. With high probability, the three most useful types of components will be:

  1. JButton: display a button with custom text on the button. We will learn how to respond to clicks on the button later.
  2. JTextField: an area where the user can type. We can retrieve what the user has typed at any time.
  3. JLabel: A label for writing text to display to the user.

Each time we want one of these components, we will declare a variable of that type, and then add it to our JPanel. These variables will be instance variables, meaning they will be declared not inside a particular method, and will usually be declared private. (If you don't understand that or haven't seen it before, that's OK. Just treat it like a normal variable that you declare outside the method.)

In all of our examples, all our content will be contained in a panel. You can think of a panel as an annoying little extra step that is required: A JFrame will contain one JPanel, and the JPanel will display everything we want.

Here's an example of an updated myGUI method:


private JPanel mainPanel;
private JButton goButton;
private JTextField userInput;
private JLabel label;

public myGUI() {
          goButton = new JButton("Go!");
	  userInput = new JTextField(20);
	  label = new JLabel("Enter a word:");

	  mainPanel = new JPanel();
	  mainPanel.add(label);
	  mainPanel.add(userInput);
	  mainPanel.add(goButton);
	  
	  add(mainPanel);
	  setVisible(true);
}

Let's step through this basic example:

  1. This example contains one button (goButton), one text field (userInput) and one label (label).
  2. For each of these three components, we declare the variable (e.g., using private JButton goButton) and then inside the myGUI method, we instantiate the variable using:
goButton = new JButton("Go!");
  1. Each of the three components takes a parameter: the button takes its label (so "Go!" will appear on the button), the text field takes the length of the field (how wide it will appear on the screen) and the label takes the text you want to display.
  2. As we just mentioned, we need a JPanel which contains all the components, and is set inside the JFrame. In this case, our JPanel is called mainPanel. We then use the add method to add all of the components to the panel. Order matters here! When we add them in the order label-text field-button, they will appear in that order from left to right. If you wanted them to appear in a different order, you'd have to put the add method calls in that order.
  3. Finally, you need to add the panel to the frame using the line
  add(mainPanel);


You'll probably notice two things when you run this code:

  1. Clicking on the buttons or typing in text does nothing! This makes sense because we haven't actually added any code to process the user's actions or inputs. We'll fix that in the next section.
  2. The window isn't the right size! You have to resize the window to show all three components. This works, but we can also specify a default size for the JFrame by adding this line to the myGUI() method:
setSize(400,100);

This line can go right at the top of your myGUI() method. The two parameters are the (width,height) that you want your window to be.

Step 3: Listen carefully!

Unlike all the code we'll otherwise write in COMP 1010, the code for this GUI doesn't have a real start or end. Once the window is open and displayed, our program will just sit there waiting for something to happen. In our simple example, what we are waiting for is the "Go!" button to be clicked. This type of programming--no real start or end, waiting for something to happen--is called event driven programming.

How do we wait for events? We'll add what is called an ActionListener to our class to handle events like button clicks. First, add this import statement to your code:

import java.awt.event.*;

Then, you need to create a private inner class to be your ActionListener:

 private class ButtonListener implements ActionListener {
      public void actionPerformed (ActionEvent e) {
    	  // all your listening code goes here!!! 
      }
  }

You can take this setup as a fixed formula that will not often need to be changed. It should go after your myGUI method but before the end of your myGUI class!

Now, we need to add two different pieces of code to make this work:

  1. We need to tell the code that the goButton is being listened to by the ButtonListener. Add this line to your myGUI() method after you instantiate the goButton variable:
  goButton.addActionListener(new ButtonListener());
  1. We need to write the code that actually happens when the button is clicked. For now, let's just pop up a JOptionPane that tells the user what they typed:
 private class ButtonListener implements ActionListener {
      public void actionPerformed (ActionEvent e) {
          String userText = userInput.getText();
	  JOptionPane.showMessageDialog(null, "You typed: " + userText);
     }
  }

The entire code should now look something like this:


import javax.swing.*;
import java.awt.event.*;

public class firstGUI extends JFrame {
	public static void main (String[] args) { 
		new firstGUI();
	}



	private JPanel mainFrame;
	private JButton goButton;
	private JTextField userInput;
	private JLabel label;

	public firstGUI() {


		setSize(400,100);

		goButton = new JButton("Go!");
		goButton.addActionListener(new ButtonListener());

		userInput = new JTextField(10);
		label = new JLabel("Enter a word:");

		mainFrame = new JPanel();
		mainFrame.add(label);
		mainFrame.add(userInput);
		mainFrame.add(goButton);

		add(mainFrame);
		setVisible(true);
	}

	private class ButtonListener implements ActionListener {
		public void actionPerformed (ActionEvent e) {
			String userText = userInput.getText();
			JOptionPane.showMessageDialog(null, "You typed: " + userText);
		}
	}

}

To emphasize, any code that you want executed when the user clicks on the GO! button should be put in the actionPerfromed method. This could call other methods, this could be a long block of code, anything. If you want it done when your event occurs, it goes there.

In this case, we simply asked for the text in the text field (by using the .getText() method, and then created a new JOptionPane.showMessageDialog to display to the user what they just typed.

Step 4: Types of Components

There are many types of components that you can add to a JPanel. Here are some of the more common components.

Class Description Constructor Useful tools/methods
JButton Push button. JButton("button label text")
  • Add a listener to the button as done in the previous example.
  • Button clicks will usually be detected in the actionPerformed method as in the previous example.
  • Use the setEnabled method to enable or disable the button: myButton.setEnabled(true) lets users click on myButton, passing false as a parameter disables the button.
JTextField Text field for getting user input.
  • JTextField(width) where width is an integer value, which is the width of the text field.
  • JTextField(text) where text is a String, which is the initial value of the text field.
  • getText(): get the String that is currently in the text field. Returns a String.
  • setText(text): set the String that is displayed in the text field. Could be "" to blank the field.
JComboBox Combo box (pull down list) which allows the user to pick one item from a predefined list of choices. JComboBox(choiceArray) where choiceArray is (in its simplest form) an array of Strings which gives the individual elements to be displayed in the combo box.
  • getSelectedItem(): returns the item that the user has last clicked on in the combo box. This needs to be cast to (usually) a String, as follows:
String usersPick = (String) myComboBox.getSelectedItem()
  • addItem(item) where item will (usually) be a String. This adds one more item to your combo box.
  • removeAllItems() clears all the contents of your combo box.
  • removeItemAt(posn), where posn is an int, removes the element in spot posn of your array.
JTextArea Like a text field, but larger. This is useful for displaying large amounts of text or reading large inputs.
  • JTextArea(wid,hei) creates a new text area of size wid-by-hei. It is initially empty.
  • JTextArea(text,wid,hei) creates a new text area of size wid-by-hei and fills it with the String text. text may contain, e.g., \n for new lines.
  • getText() returns (as a String) the contents of the text area.
  • setEditable(bool): sets whether the text area can be edited. Pass a boolean value (true or false).
JPasswordField Like a text field, but hides what the user types in. Exactly like JTextField getPassword(): get the current password typed in the box. For some reason, returns an array of chars.

A visual guide to all swing components is here. Clicking on any of the components on that page will give examples of how to use the components, as well as more methods for the components.


Exercise: calculate humidex

To try out your skills, try building a GUI to do Assignment 1 Question 2 (Fall 2010). This question asks you to build a humidex calculator based on the temperature and dew point. Use this method to calculate the humidex:

        /**
	 * calcHumidex - calculates the humidex based on dew point and temperature.
	 *
	 * @param D - dew point
	 * @param T - air temperature
	 *
	 * @return - humidex calculated from parameters.
	 */

	public static double calcHumidex ( double D, double T) {

		double e;
		double h;

		e = 6.11 * Math.pow(Math.E,5417.77530 * ( 1 / 273.16 - 1/( 273.16 + D)));		
		h = 0.5555 * (e - 10);

		return Math.round( (T + h)*10.0)/10.0;

	}

Here's a possible set up of the GUI (shown with size 700x100):

Swing.jpg

Exercise: compute windchill

Here's a method, adapted from the Winter 2011 assignments, for computing the windchill:

public static double calculateWindchill (double windspeed, double temperature) {

	    double velocityPower, windchill;
	    
	    //calculate windchill
	    velocityPower = Math.pow(windspeed, 0.16) ;
	    
	    if (windspeed >= 5) {
	    
	    	windchill = 13.12 + 0.6215 * temperature - 11.37 * velocityPower
	        + 0.3965 * temperature * velocityPower ;
	    } else {
	    	windchill = temperature + (-1.59 + 0.1345 * temperature) * windspeed / 5.0 ;
	    }
	    
	    return windchill;

	}

The full solution is available here.