GUI Programming Exercise
This exercise is in lieu of a GUI lab. There is nothing to hand in. Work through the steps and ask your teacher or another student if you need help understanding something.
Remember the "Three Steps to GUI Programming" that we covered yesterday:
- Make a background window
- Put Components into the window
- Add Listeners to the Components
First GUI
Here is our first GUI code. Copy this to a text file and run it in Java:
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GUITest1 {
public static void main(String[] args) {
JButton button1=new JButton("My first JButton");
JPanel myPanel=new JPanel(new BorderLayout());
myPanel.add(button1, BorderLayout.NORTH);
JFrame window = new JFrame("My first Swing Window");
window.add(myPanel);
window.setSize(400, 200);
window.setVisible(true);
}
}
Mods to the GUI
One of the best ways to learn about any new programming concept is to write a program with that concept and experiment with it. It is okay to just change code around to see how it works.
What is the codeflow in a GUI?
Did you notice anything strange about starting and stopping your program? It acts differently than the command-line apps you have been using. You might need to use Ctrl-C to end the program after you close the GUI.
The command-line does not give a prompt when the program is running. Does it block on a particular command? Do a test to find out. Put a print statement after every line in the main() method. This will tell you where the program blocks, if at all.
Remove the print statements once you are done. Your results from this experiment should answer one question (Does the program block in main()?) and should also raise a new one (Where does the program block?)
The short answer is that GUI code spawns threads that listen for Events. The main() method is only one thread. There are hidden threads blocking that are waiting for user input. Java does not exit until all of its threads finish running.
What happens if I comment out that "window.setVisible()" line?
Try it and see.
You probably guessed right that the GUI would not display. Does the terminal act differently now? Did you figure out what call starts those extra GUI threads?
Can I create more than one window in my program?
Let's do some trial-and-error to find out.
- Save your program as GUITest2.java so we can undo this test easily.
- Create a method named private static void test()
- Move all of the code from your main() method to test().
- Add the following line to main(): test(); test(); test();
- Run your program and see what happens.
Revert to GUITest1.java after you are done.
This test might provide some insight into why Java does not stop automatically what you close a GUI. If it did, then shutting down a single window would cause the others to shut down as well.
Add a Listener
Let's add a MouseListener to listen to mouse clicks on the button.
We are actually going to use the "MouseAdapter" vice "MouseListener". You can search for the differences online. Basically, we chose the one that is easier to work with.
Add the following class inside class GUITest1, just above your main() method:
public static class Button1Adapter extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
((JButton)e.getComponent()).setText("I have been clicked");
}
}
You will need to add two import statements:
import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent;
Also add the following line to main() to connect your button to your listener:
button1.addMouseListener(new Button1Adapter());
Click the button on the GUI to see what it does.
Making the GUI close more cleanly
We are going to need a second Listener for this. A GUI program usually has many Listeners. Most have at least one for each button, text box, etc. It is possible to have many more.
You should have noticed by now that the user has to hit Ctrl-C to close Java after running your GUI. This is annoying. It means that Java is not really stopping when our GUI closes.
You know that button with the red "X" that closes a GUI? It turns out, that is just another button, and you can write a Listener for it.
We are going to write this one one using an "Anonymous class".
| NOTE - Anonymous classes were briefly mentioned in yesterday's lecture notes. If you look at the code, you can see that we are creating an object of type WindowAdapter and overriding a single method. You do not ever need to use anonymous classes, but you should be able to read them when you see them. |
Add the following to your main() method:
window.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
You will need to add two import statements:
import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent;
Compile and run this code. Do you notice that it behaves differently when it shuts down? You should no longer need Ctrl-C to end the Java session. You should generally put this Listener in every GUI you write.
Adding a second Listener to our button
Add the following lines of code inside your Button1Adapter class:
private static int count = 0;
public void mouseEntered(MouseEvent e) {
super.mouseEntered(e);
count++;
((JButton)e.getComponent()).setText(count+"");
}
This will cause the text of the button to change every time you move the mouse over it. The Click functionality should still work.
Complete demo code
Here is the complete listing of the changes we have made. Use this if you are having problems making something work.
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GUITest1 {
public static class Button1Adapter extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
((JButton)e.getComponent()).setText("I have been clicked");
}
private static int count = 0;
public void mouseEntered(MouseEvent e) {
super.mouseEntered(e);
count++;
((JButton)e.getComponent()).setText(count+"");
}
}
public static void main(String[] args) {
JButton button1=new JButton("My first JButton");
button1.addMouseListener(new Button1Adapter());
JPanel myPanel=new JPanel(new BorderLayout());
myPanel.add(button1, BorderLayout.NORTH);
JFrame window = new JFrame("My first Swing Window");
window.add(myPanel);
window.setSize(400, 200);
window.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
window.setVisible(true);
}
}
Next Steps
The best way to learn about code is by playing with it. Pick one of the following tasks and implement it in your GUI app:
- Change the color of the button to a new random color every time you click on it.
- Make the button smaller and in the center of the window.
- Draw the window with a java.awt.Frame instead of a javax.swing.JFrame.
- Draw the button with a java.awt.Button instead of a javax.swing.JButton.
- Add a second button. Have each button change the text of the other.
- Use a layout manager to create a 2x2 grid of buttons.
- Implement a tic-tac-toe game with 9 buttons. LMB for X and RMB for O.
- Disable the button every time the mouse hovers over it. Re-enable it when the mouse leaves.