Chapter 11
|
Modified: |
Chapter 11 discusses elements of graphical user interfaces (GUI); such as buttons and the events, such as mouse clicks, that provide user control.
GUIs, at their simplest, consist of some visible object, such as a button, that can produce an event, such as a mouse click. When the button is clicked, a mouse clicked event is produced, generating a call to some designated method. What happens when the button is clicked is determined by the method called. Connecting an event to a method is defined in a Java inner-class. More later in examples.
Java has two approaches to GUI delivery; as a regular program in a frame and as an Applet. The key difference is that an Applet can be executed by a Web browser, otherwise programming is the same. The following has examples of both approaches.
Many standard graphical user interface objects are defined in Java; buttons, labels, text boxes, sliders, lists, menus, etc. Graphic objects such as balls, houses, etc. must be implemented; we will look first at those since in some ways are simpler.
Applets are Java programs that can run within a browser such as IE or the appleviewer. An HTML file is required that contains class file and window size information for the browser. One problem of applets are serious security restrictions due to delivery over the Internet; generally security restrictions are on file access or other computer hardware.
The following is a simple example of Java Applet graphics, drawing a rectangle.
Exercise 1 - Examining the Simple Applet In BlueJ
- Create a new project named Ch11
- Create a new class named Simple.
- Open class Simple in the editor.
- Copy, paste and compile the following Simple code. BlueJ should appear at top right.
import java.awt.*;
import java.applet.*;
public class Simple extends Applet
{
public void paint(Graphics g) {
g.drawRect(30, 20, 10, 50);
}
}
- Right click on Simple class icon; select Run Applet
- Select Run Applet in appletviewer as at right.
- Simple should appear as at right in a Applet Viewer window.
Discussion
- import java.awt.*; - The graphics library.
- import java.applet.*; - The applet library.
- class Simple extends Applet - Inherit from the Applet class.
- public void paint(Graphics g) - Called whenever the graphics display needs painted, such as after resizing the window. g is the graphics display. Can be called indirectly by: repaint().
- g.drawRect(30, 20, 10, 50); - Draw a rectangle of width 10 and height 50 on the graphics display g at top-left corner (30, 20).
Movement as in Follow the Bouncing Ball
Frames are used for programs residing on the computer that have full access to the file system but cannot be used in a browser. We could use either Applet or frames here.
Movement is produced by repetitively show'ing and erase'ing the same graphic. The consists of two classes:
- BouncingBall - inherits Frame on which to display the Ball and the method:
- bounce - erases, moves and shows the ball.
- Ball - defines a Ball and methods:
- move - moves the Ball one step in the current direction, if frame edge hit changes direction.
- show - displays the Ball
- erase - erases the Ball
Exercise 2 In BlueJ
- Copy, paste and compile the BouncingBall and Ball classes below.
- Create a BouncingBall object.
- If not Ball is displayed, minimize and reopen, the ball should appear. Remember that paint() is called when the display changes.
- Call the bounce() method several times.
- Increase the dx and dy values in Ball. Call the bounce() method several times.
- Change bounce() to erase, move and show the ball 10,000 times.
Ctrl+Shift+R to reset the Virtual Machine, if necessary.
- Did you see the Ball bounce? Suggest a way to fix.
- Drag the BouncingBall window to resize.
- Minimize and reopen.
Exercise 3
Use another solution that slows the ball by putting the execution to sleep for 10 milliseconds by:
try { Thread.sleep(10); } catch(Exception e) {}
import java.awt.*;
public class BouncingBall extends Ball
{
public void bounce()
{
erase();
move();
draw();
}
}import java.awt.*; class Ball extends Frame { Graphics graphics=null; static final int WIDTH = 20; // Ball height, width static final int HEIGHT = 20; int x = 150; // Current x,y int y = 60; int dx = 2; // Distance moved int dy = 2; public Ball() { setSize(300,300); // Size setVisible(true); setBackground(Color.blue); // Color graphics = getGraphics(); // Frame reference } public void paint(Graphics graphics) { draw(); } public void erase() { graphics.setColor(Color.white); // Erase ball graphics.fillOval(x,y,WIDTH,HEIGHT); } public void draw() { graphics.setColor(Color.red); // Draw ball graphics.fillOval(x,y,WIDTH,HEIGHT); } public void move() { x = x + dx; // Move x y = y + dy; // Move y if (x < 0) { // Hit left wall x = 0; dx = -dx; } if (x + WIDTH >= getWidth()) { // Hit right wall x = getWidth() - WIDTH; dx = -dx; } if (y < 0) { // Hit top wall y = 0; dy = -dy; } if (y + HEIGHT >= getHeight()) { // Hit bottom wall y = getHeight() - HEIGHT; dy = -dy; } } }
GUIs, at their simplest, require some visible object, such as a button, that can produce an event, such as a mouse click.
All the programs we have seen execute one statement after another in sequence, in predictable order. Humans work asynchronously, as when clicking a mouse button, in unpredictable order. Event handling responds when the event occurs, such as clearing the screen when clicking a mouse, to make the GUI believable.
When the button is clicked, a mouse clicked event is produced, generating a call to some designated method. What happens when the button is clicked is determined by the method called. Connecting an event to a method is defined in a Java inner-class.
The following illustrates a simple applet that displays a single button and handles several types of events.
Exercise 4 - Examining the Applet In BlueJ
- Create a new project named Ch11
- Create a new class named MyAPPLET.
- Open class MyAPPLET in the editor.
- Copy, paste and compile the following MyAPPLET code. BlueJ should appear at right.
- Right click on MyAPPLET class icon; select run Applet
- Select Run Applet in web browser as at right.
- MyAPPLET should appear as at right in a Web browser window.
- Pass the mouse over the Don't hit me button.
- Count all the distinct labels on the button (look for setText).
- Click the button.
- Examine the Java below. Determine where in the program each button label is produced.
- 1Enter
- Button1
- 1Click
- 1Exit
- Where is the button constructed?
- Read the documentation on MouseListener. Add the inner-class and other code to change the label to "1Press" when the mouse is pressed.
- Test.
- Click Close.
Exercise 5
- Add the method click():
public void click() {
button1.setLabel("1Click");
}- Make changes to call the click() method on a mouse click event.
- Test.
- Click Close.
Exercise 6
- Add another button named button2.
- Label as "Button2".
- On a mouse click event, change the "Button2" label to "2Click".
- Test by clicking on button1. What happens?
Exercise 7
- In Exercise 6, button1 and button2 events were both handled in a single MouseListener, mouseListener1.
- Clicking button1 or button2 executed the same mouseClicked method.
- We need a separate MouseListener for each button, with separate mouseClicked, etc. methods.
- Copy, paste and compile the MyAPPLET code below again.
- Duplicate the effects of button1 code for button2.
- Test.
MyAPPLET.java
MyAPPLET.html
import java.awt.*; import java.awt.event.*; import java.applet.*; public class MyAPPLET extends Applet { final Button button1 = new Button("Button1"); public MyAPPLET() { MouseListener mouseListener1 = new MouseAdapter() { public void mouseClicked(MouseEvent e) { button1.setLabel("1Click"); } public void mouseEntered(MouseEvent e) { button1.setLabel("1Enter"); } public void mouseExited(MouseEvent e) { button1.setLabel("1Exit"); } }; button1.addMouseListener(mouseListener1); add(button1); setVisible(true); } }HTML
Because applets run in browsers, some HTML is required to run the applet. The following defines the MyAPPLET.class to be run when the browser loads MyAPPLET.html file.
<APPLET code="MyAPPLET.class" width=100 height=100> </APPLET>
Exercise 8 - Running the Applet in a browser In IE
- Locate the Ch11 directory.
- Open the MyAPPLET.html file in IE.
Inner-classes are used to connect graphical object events such as a click with some action. There are 3 parts as exemplified by a mouse and a button:
- The MouseListener listens and detects all mouse events.
- The inner-class connects a specific mouse event (mouseClicked) with some action performed (button1.setLabel("1Click"); ). This is where the event is handled.
- The button and listener are connected so that the clicking of the button results in the appropriate action.
1. MouseListener mouseListener1 = new MouseAdapter() {
2. public void mouseClicked(MouseEvent e) {
button1.setLabel("1Click");
}
};3. button1.addMouseListener(mouseListener1);
Buttons and drawing can be combined to produce a rich GUI. The basic idea is that the button and applet (or frame) display are distinct, a mouse clicking a button is separate from a mouse in the rest of the display. Listeners can then connect a button mouse click to the button event handler.
The following series of three examples consist of:
- Display the mouse location as moved across the display, uses a label to display x,y values.
- Draw a line as the mouse is dragged across the display. Cannot clear the display.
- Draw a line and clear the display. Combines button with graphics.
Exercise 9
- The key part is displaying the x,y position of the mouse as it is moved over the display.
The label is set to the x,y values by:
label.setText(e.getX() + "," + e.getY());
In BlueJ
- Create a new class named MyAPPLET9; copy, paste, compile and test the following.
import java.awt.*; import java.awt.event.*; import java.applet.*; public class MyAPPLET9 extends Applet { final Label label = new Label("Mouse x, y location"); public MyAPPLET9() { MouseMotionListener mouseMotionListener2 = new MouseMotionAdapter() { public void mouseMoved(MouseEvent e) { label.setText(e.getX() + "," + e.getY()); } }; this.addMouseMotionListener(mouseMotionListener2); add(label); setVisible(true); } }
Exercise 10 Draws a line as the mouse is dragged across the display. Cannot clear the display except by closing and reopening window.
- Whenever the mouse is dragged the x,y position is stored in an ArrayList in the mouseDragged method.
- repaint() calls paint() method; draws the line by connecting the dots of x,y values in the ArrayList.
In BlueJ
- Create a new class named MyAPPLET10; copy, paste, compile and test the following.
- Comment out the repaint(). What is the effect?
- Why is a repaint() needed when drawing lines but not when using a label?
- Try minimizing and reopening the window.
- Find one flaw with the behavior of this design.
import java.awt.*; import java.awt.event.*; import java.applet.*; import java.util.*; public class MyAPPLET10 extends Applet { ArrayList <Point> points = new ArrayList <Point> (); Button button = new Button("Clear"); public MyAPPLET10() { MouseMotionListener mouseMotionListener2 = new MouseMotionAdapter() { public void mouseDragged(MouseEvent e) { points.add( new Point(e.getX(), e.getY() )); repaint(); } }; this.addMouseMotionListener(mouseMotionListener2); setVisible(true); } public void paint(Graphics g) { Point p1 = points.get(0); Point p2; int x1, y1, x2, y2; for(int i = 1; i < points.size(); i++) { p2 = points.get(i); x1 = (int) p1.getX(); y1 = (int) p1.getY(); x2 = (int) p2.getX(); y2 = (int) p2.getY(); g.drawLine(x1, y1, x2, y2); p1 = p2; } } }
Exercise 11 Draw a line as the mouse is dragged across the display. Clears the display by button click.
- When mouse is pressed in display area, marks the start of a visible line.
- Whenever the mouse is dragged the x,y position is stored in an ArrayList in the mouseDragged method of start and next x,y point.
- repaint() calls paint() method; draws the line by connecting the dots of x,y values in the ArrayList.
- Clicking clear button destroys ArrayList holding points.
- Uses a layout manager to correctly place the clear button at top-center of display.
In BlueJ
- Create a new class named MyAPPLET11; copy, paste, compile and test the following.
- Mouse events are used for two different purposes:
- detect a click of the clear button,
- detect mouse down outside of the clear button.
Locate the code for each.
How is one mouse event distinguished from the other?
- What is the purpose of:
button.addMouseListener(mouseListener1);
- Locate the repaint() calls. Why is each needed?
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.*;
public class MyAPPLET11 extends Applet {
ArrayList <Point> points = new ArrayList <Point> ();
Point startp;
Button button = new Button("Clear");
public MyAPPLET11() {
MouseListener mouseListener1 = new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
points=new ArrayList <Point> (); // Clear points
repaint();
}
};
MouseMotionListener mouseMotionListener = new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
Point endp = startp; // Mark line segment
startp = new Point(e.getX(), e.getY() ); // by adding start and
points.add(endp); // and end points
points.add(startp);
repaint();
}
};
MouseListener mouseListener2 = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
startp = new Point(e.getX(), e.getY() ); // Mark line start point
}
};
this.addMouseMotionListener(mouseMotionListener);
this.addMouseListener(mouseListener2);
button.addMouseListener(mouseListener1);
setLayout(new FlowLayout()); // Layout manager
setSize(300,300);
add(button);
setVisible(true);
}
public void paint(Graphics g) { // Connect the dots
Point p1, p2;
int x1, y1, x2, y2;
for(int i = 0; i < points.size()-2; i=i+2) {
p1 = points.get(i);
x1 = (int) p1.getX();
y1 = (int) p1.getY();
p2 = (Point) points.get(i+1);
x2 = (int) p2.getX();
y2 = (int) p2.getY();
g.drawLine(x1, y1, x2, y2);
}
}
}
Game programming is more interesting and challenging because of the movement, requiring efficient design to keep up, and creation of unique graphics, rather using the buttons, sliders, etc.
Games are simulations of real life (e.g. auto racing) which obey physical laws or make believe (e.g. Super Mario) which must be believable.
The game of Pong was reported to be the first interactive computer game and remains a standard example of a simple action game. It blends the real notion of bouncing a ball off a paddle with some make believe.
Our design has three classes:
- Pong
- Defines the graphic frame
- Constructs a Ball and a Paddle
- Bounces the Ball
- Detects a collision between the Ball and Paddle, reversing direction of the Ball
- Ball
- Displays a Ball
- Moves the Ball each time called, bouncing off walls.
- Paddle - The paddle is a yellow rectangle on the left side of the frame. When the mouse is inside the rectangle, the paddle follows the up and down movement of the mouse.
- Displays a Paddle
- Moves the Paddle with the mouse.
We will use the bouncing ball as the starting point.
Exercise 12 In BlueJ
- Create three new classes named Pong, Ball and Paddle; copy, paste, compile the following.
- Create a Pong object, open the display window, move the mouse of the yellow paddle.
- Call the bounce() method of the Pong object to start the Ball bouncing.
- Ctrl+Shift+R to reinitialize the virtual machine and close the Pong game window.
Exercise 13 - Pong.
- There is a subtle flaw only obvious when Pong window is displayed initially. To observe the flaw, minimize all windows except the main BlueJ window and create a Pong object.
- What is the flaw?
- Minimize and reopen the Pong window. What happened and why?
- Correct the flaw.
- Where is the ball movement speed controlled?
- Change the ball movement speed to be faster or slower.
- Comment out the delay and replace the delay with a for statement.
- What doe the paint() method do? Why is the paint() method needed?
- The Ball is moved in the following; how does the Paddle move?
while (ball.moving()) {
ball.move();
if(collision())
ball.reverse();
try { Thread.sleep(5); } catch(Exception e) {}
}
Exercise 14 - Ball.
- Fields dx and dy determine the direction the Ball is moving.
- Change reverse() so that only one direction is changed. What happens when run? Why?
- There is no erase() method but the Ball disappears? Why?
- move() does not call show()! What displays the Ball?
Exercise 15 - Paddle.
- Field dy determines the direction the Paddle is moving. Why is dx not needed also?
- Why is the mouse listener added to the frame? What is the frame?
- What happens when frame.repaint() is commented out?
- What does it do?
- This is not good object oriented style, where the Paddle object affects the behavior of the Pong object. What is it about the Paddle that we stuck with for now?
- There is no erase() method but the Paddle disappears? Why?
- move() does not call show()! What displays the Paddle? Why is this necessary?
import java.awt.*;
public class Pong extends Frame {
Ball ball;
Paddle paddle;
public Pong() {
setSize(500,600); // Frame size
setVisible(true);
ball = new Ball(this);
paddle = new Paddle(this);
}
public void paint(Graphics g) {
if( ball != null) ball.show();
if( paddle != null) paddle.show();
}
public void bounce() {
ball.reset(); // Reset the ball to 'moving=true'
while (ball.moving()) { // Ball moves when 'moving==true'
ball.move();
if(collision()) // Reverse direction on ball/paddle collision
ball.reverse();
try { Thread.sleep(5); } catch(Exception e) {}
}
}
public boolean collision() { // Did ball and paddle collide?
return
ball.getX() >= paddle.getX()-paddle.getWIDTH() &&
ball.getX() <= paddle.getX()+paddle.getWIDTH() &&
ball.getY() >= paddle.getY()-paddle.getHEIGHT() &&
ball.getY() <= paddle.getY()+paddle.getHEIGHT();
}
}import java.awt.*;
class Ball {
Graphics graphics;
Frame frame;
static final int WIDTH = 20, HEIGHT = 20;
boolean moving = true;
int x = 100, y = 100, dx = 2, dy = 2; // Initial ball location
public Ball(Frame frame) {
this.frame = frame;
graphics = frame.getGraphics();
}
public int getX() { return x;}
public int getY() { return y;}
public void reverse() { dx=-dx; dy=-dy; } // Reverse ball direction
public void show() {
graphics.setColor(Color.red); // Show ball
graphics.fillOval(x,y,WIDTH,HEIGHT);
}
public boolean moving() { return moving;} // Is ball moving
public void reset() { moving = true; } // Set ball moving
public void move() {
x = x + dx; // Move x
y = y + dy; // Move y
Dimension d = frame.size(); // Size frame
if (x < 0) { x = 0; dx = -dx; moving=false; } // Hit left
if (x + WIDTH >= d.width) { x = d.width - WIDTH; dx = -dx; } // Hit right
if (y < 0) { y = 0; dy = -dy;} // Hit top
if (y + HEIGHT >= d.height) { y = d.height - HEIGHT; dy = -dy; } // Hit bottom
frame.repaint();
}
}import java.awt.*;
import java.awt.event.*;
import java.applet.*;
class Paddle { // Paddle follows mouse on left
Graphics graphics;
Frame frame;
static final int WIDTH = 40, HEIGHT = 60;; // Paddle size
int x = 0, y = 0, dy = 5;
public Paddle(Frame frame) {
this.frame = frame;
graphics = frame.getGraphics();
MouseMotionListener mouseMotionListener = new MouseMotionAdapter() { // Paddle follows mouse
public void mouseMoved(MouseEvent e) {
int xm=e.getX(), ym=e.getY(); // Mouse x,y
if(xm>=x && xm<=x+WIDTH) { // Mouse same x as paddle?
if(ym+dy>=y) y=ym+dy; // Mouse dy below?
else if(ym-dy<=y) y=ym-dy; // Mouse dy above?
move(); // Move paddle to mouse
}
}
};
frame.addMouseMotionListener(mouseMotionListener);
}
public int getX() { return x;}
public int getY() { return y;}
public int getHEIGHT() { return HEIGHT;}
public int getWIDTH() { return WIDTH;}
public void show() {
graphics.setColor(Color.yellow); // Show paddle
graphics.fillRect(x,y,WIDTH,HEIGHT);
}
public void move() { // Move paddle
frame.repaint();
}
}
GUI programming is challenging, requiring about 65% of the project development time; it is also complex, we have only scratched the surface of the using buttons, sliders, etc.; we have most of the tools, but not all required for GUI development.
Main ideas
- Java supplies an extensive graphics library for drawing and predefined objects such as buttons, sliders, etc.
- Applets run in a browser with limited access to the hardware such as file systems.
- paint() is called whenever the graphics frame or applet needs drawn, such as changing the window size; the graphics are erased first. repaint() calls the paint() method.
- Events, such as mouse clicks, are asynchronous, can occur at any point in the program execution. Events initiate the call to a method defined in a inner-class.