INFORMATION & COMPUTER SCIENCE DEPARTMENT, KFUPM
ICS201, SECTIONS 52 (002
Semester)
INTRODUCTION TO COMPUTER SCIENCE
LAB #04 Experience with
Graphical User Interfaces and Event Handling
Instructor: Bashir M. Ghandi
To gain experience with:
In
Example 2 of Lecture 12, we considered an applet that tracks the position of the
mouse and displays the coordinates of the point at which the different mouse
events take place and prints then on the DOS window. A better behavior
for this applet could be to display the message on the applet window
itself. This is what the first example below does:
import java.applet.Applet; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.TextField; public class AWTMouseSpyApplet extends Applet implements MouseListener{ private TextField textField = new TextField(23); public void init() { add(textField); addMouseListener(this); } public void mouseClicked(MouseEvent me){ textField.setText("Clicked at ("+me.getX()+", "+me.getY()+")"); } public void mouseEntered(MouseEvent me){ textField.setText("Entered at ("+me.getX()+", "+me.getY()+")"); } public void mouseExited(MouseEvent me){ textField.setText("Exited at ("+me.getX()+", "+me.getY()+")"); } public void mousePressed(MouseEvent me){ textField.setText("Pressed at ("+me.getX()+", "+me.getY()+")"); } public void mouseReleased(MouseEvent me){ textField.setText("Released at ("+me.getX()+", "+me.getY()+")"); } } |
Notes:
The only changes made
to the program in Example 2 of Lecture 12 to obtain the above are:
We
now modify Example 1 slightly by using JApplet and JTextfield
instead of Applet and Textfield. Recall that for the JApplet,
we cannot call the add() method of Component directly to add the
desired components. We have to get the content pane of the JApplet window
first and then add the components.
Make
these changes and save the new applet as SwingMouseSpyApplet and run it side-by-side
the one using the AWT components. Do you notice any differences?
One
obvious difference you'll notice is that the text field onto which mouse
coordinates are written spans the whole applet window in the JApplet
version. This is because the default layout manager for the content
pane of JApplet window is BorderLayout,
while that of applets is FlowLayout
(as inherited from Panel). Thus, if you
want the text area in the JApplet-based program to occupy a small
portion of the window as in the Applet-based program, you have to change
the layout of the content pane to FlowLayout. Do it!
For
both these programs, you'll notice that the mouse coordinate displayed in the
text field can be edited. You can make this message uneditable using the setEditable()
method. Again, do this!
The following figure should give an idea of the
differences between AWT frames and Swing Frames. Note that the requirement of getting
the content pane applies to JDialog and JInternalFrame instances
as well.
The
next minor modification is to change the program into an application. You need
to make the following changes:
import java.awt.Container; import java.awt.FlowLayout; import java.awt.event.MouseEvent; import java.awt.event.WindowEvent; import java.awt.event.MouseListener; import java.awt.event.WindowAdapter; import javax.swing.JFrame; import javax.swing.JTextField; public class MouseSpyApplication extends JFrame implements MouseListener{ private JTextField textField = new JTextField(23); public MouseSpyApplication() { Container cp = getContentPane(); cp.setLayout(new FlowLayout()); cp.add(textField); textField.setEditable(false); addMouseListener(this); } public void mouseClicked(MouseEvent me){ textField.setText("Clicked at ("+me.getX()+", "+me.getY()+")"); } public void mouseEntered(MouseEvent me){ textField.setText("Entered at ("+me.getX()+", "+me.getY()+")"); } public void mouseExited(MouseEvent me){ textField.setText("Exited at ("+me.getX()+", "+me.getY()+")"); } public void mousePressed(MouseEvent me){ textField.setText("Pressed at ("+me.getX()+", "+me.getY()+")"); } public void mouseReleased(MouseEvent me){ textField.setText("Released at ("+me.getX()+", "+me.getY()+")"); } public static void main(String[] args) { MouseSpyApplication application = new MouseSpyApplication(); application.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { System.exit(0); } }); application.setTitle("Applet Coverted into Application"); application.setSize(300, 300); application.show(); } } |
Now
that we have modified the applet, converted it into an application we are ready
to make the program into both an applet and an application. It is clear
from the above examples that the program should contain both the applet code as
well as the main() method. The steps for making an applet into an
application could be summarized thus:
import java.awt.Container; import java.awt.FlowLayout; import java.awt.event.MouseEvent; import java.awt.event.WindowEvent; import java.awt.event.MouseListener; import java.awt.event.WindowAdapter; import javax.swing.JApplet; import javax.swing.JFrame; import javax.swing.JTextField; public class MouseSpyAppletAndApplication extends JApplet implements MouseListener{ private JTextField textField = new JTextField(23); public void init() { Container cp = getContentPane(); cp.setLayout(new FlowLayout()); cp.add(textField); textField.setEditable(false); addMouseListener(this); } public void mouseClicked(MouseEvent me){ textField.setText("Clicked at ("+me.getX()+", "+me.getY()+")"); } public void mouseEntered(MouseEvent me){ textField.setText("Entered at ("+me.getX()+", "+me.getY()+")"); } public void mouseExited(MouseEvent me){ textField.setText("Exited at ("+me.getX()+", "+me.getY()+")"); } public void mousePressed(MouseEvent me){ textField.setText("Pressed at ("+me.getX()+", "+me.getY()+")"); } public void mouseReleased(MouseEvent me){ textField.setText("Released at ("+me.getX()+", "+me.getY()+")"); } public static void main(String[] args) { MouseSpyAppletAndApplication applet=new MouseSpyAppletAndApplication(); applet.init(); JFrame application = new JFrame(); application.getContentPane().add(applet); application.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { System.exit(0); } }); application.setTitle("Applet Coverted into Application"); application.setSize(300, 300); application.show(); } } |
Now
you can run this applet both using the appletviewer as well as using the java
virtual machine. Note that the line
application.setSize(300,300);
in
the main() method above sets the dimensions of the window into which the
applet will be displayed when run as an application. Where are the
dimensions set when run on the browser?
Since
ICS102, you have taken the signature of the main() method from us on
trust. You would have wondered what purpose the parameter to this method
serves. In this section we will illustrate the use of that parameter.
The
window dimension in the above application is fixed. If you wish to change
that then you have to change the setSize() method and recompile. A
better way of doing this modification without recompilation is to pass the
dimensions as command-line parameters.
To
do this, we add the following fields and methods:
private static int width, height;
static void setDefaultSize() {
width = 300;
height = 300;
}
if (args.length == 2 ) {
width = Integer.parseInt( args[0] );
height = Integer.parseInt( args[1] );
} else setDefaultSize(); // no command-line arguments
application.setSize(width,height);
These
two fields are now used to set the display window dimensions when the program
is run as an application. With this you can now call the program, for
example, as follows:
C:\>java MouseSpyAsAppletAndApplication 400 300
C:\>java MouseSpyAsAppletAndApplication 500 700
C:\>java MouseSpyAsAppletAndApplication
From the above ideas we are
going to build an applet-cum-application program which, on button presses,
generates and draws graphics shapes at random positions in the program's
window.
In similarity with the
program in Example 1, this program has a JPanel (compared to the text
field in Example 1) where the random graphics objects will be drawn.
Panels are one of the
containers frequently used to properly lay out different components inside a
container.
·
JPanels, like other Swing components, inherit the paintComponent()
method from JComponent.
·
This
method, which needs to be overridden, helps to draw graphics properly.
·
Unlike
buttons, JPanels do not create events but can recognize lower-level
events like mouse and key events.
Here is the code that specifies a dedicated panel for drawing the figures. We override the paintComponent() method to draw a random shape based on the user's selection
import java.awt.Graphics; import javax.swing.JPanel; public class DrawingPanel extends JPanel { private
int currentChoice = -1; // don't draw
first time private
int width = 100, height = 100; public
DrawingPanel(int w, int h) { width
= ( w >= 0 ? w : 100 );
height = ( h >= 0 ? h : 100 ); } public void paintComponent(Graphics g) {
super.paintComponent( g );
switch( currentChoice ) {
case 0:
g.drawLine( randomX(), randomY(), randomX(), randomY() );
break;
case 1:
g.drawRect( randomX(), randomY(), randomX(), randomY() );
break;
case 2:
g.drawOval( randomX(), randomY(), randomX(), randomY() );
break; }
} public void setCurrentChoice(int c) {
currentChoice = c;
repaint(); } private
int randomX() {
return (int) (Math.random() * width); } private
int randomY() {
return (int) (Math.random() * height); } } |
We now turn to the applet
which makes use of the panel to draw the random figures.
import java.awt.GridLayout; import java.awt.BorderLayout; import java.awt.Container; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JPanel; public class RandomShapes extends JApplet { private JButton choices[]; private String names[] = {"Line", "Rectangle", "Oval" }; private JPanel buttonPanel; private DrawingPanel drawingArea; private int width = 300, height = 200; public void init() { drawingArea = new DrawingPanel( width, height ); choices = new JButton[ names.length ]; buttonPanel = new JPanel(); buttonPanel.setLayout(new GridLayout( 1, choices.length ) ); ButtonHandler handler = new ButtonHandler(); for ( int i = 0; i < choices.length; i++ ) { choices[i] = new JButton( names[i] ); buttonPanel.add( choices[i] ); choices[i].addActionListener(handler); } Container c = getContentPane(); c.add(buttonPanel, BorderLayout.NORTH ); c.add(drawingArea, BorderLayout.CENTER ); } public void setWidth( int w ) { width = ( w >= 0 ? w : 300 ); } public void setHeight( int h ) { height = ( h >= 0 ? h : 200 ); } public static void main( String args[] ) { int width, height; if ( args.length != 2 ) { // no command-line arguments width = 600; height = 400; } else { width = Integer.parseInt( args[ 0 ] ); height = Integer.parseInt( args[ 1 ] ); } // create window in which applet will execute JFrame applicationWindow = new JFrame( "An applet running as an application" ); applicationWindow.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ); RandomShapes appletObject = new RandomShapes(); appletObject.setWidth( width ); appletObject.setHeight( height ); appletObject.init(); applicationWindow.getContentPane().add( appletObject ); applicationWindow.setSize( width, height ); applicationWindow.show(); } private class ButtonHandler implements ActionListener { public void actionPerformed( ActionEvent e ) { for ( int i = 0; i < choices.length; i++ ) if ( e.getSource() == choices[ i ] ) { drawingArea.setCurrentChoice(i); break; } } } } |
Enhance the above program as suggested below.
1.
Modify
the buttons labels as: RandomCar, RandomTruck and RandomShape
respectively. When the first button is pushed, it should display an image
of a car at a random location on the window. The other two buttons should
do similarly but for trucks and random graphic shapes (line, rectangle and
circle). Hint: Refer to Exercise P9.6 on Page 392-393 of your Java
Textbook for the car and truck drawings.
2.
You
will notice that when the random graphics are displayed, they are sometimes not
visible on the window. Is it possible to force the random graphics
drawing to be displayed within the set window size? Modify the program to
achieve this or explain why this may not be done and the possible implications.