Given by Geoffrey C. Fox, Nancy McCracken at NAVO Tutorial on Sept 23 1998. Foils prepared Sept 21 1998
Outside Index
Summary of Material
This version of Part3 is Fully Upgraded to Java1.1 with critical AWT changes |
In Part 1 and 2 of the Tutorial We Covered:
|
In This Part of the Java Tutorial We Cover: |
Introduction to Threads |
Graphics in more detail
|
Abstract Windowing Toolkit
|
And in the Remaining Part of the Java Tutorial We Cover:
|
Outside Index Summary of Material
http://www.npac.syr.edu/projects/tutorials/Java/ |
Instructors: Geoffrey Fox , Nancy McCracken |
Syracuse University |
111 College Place |
Syracuse |
New York 13244-4100 |
The AWT has two different schemes for creating all or parts of applet windows:
|
(0,0) (width,0) |
(0,height) (width,height) |
Java Graphics Pixel Coordinate System |
Graphics class has methods to construct basic two dimensional images
|
drawString (String text, x, y) |
drawLine (x1, y1, x2, y2) |
drawRect (x, y, width, height), fillRect (...), |
drawOval (...), fillOval (...), |
drawRoundRect (x, y, width, height, arcWidth, arcHeight)
|
draw3DRect (x, y, width, height, Boolean b)
|
drawArc (x, y, width, height, startAngle, arcAngle), fillArc(..), |
drawPolygon(int xPoints[], int yPoints[], n); |
In every applet or windows application, the windowing system creates an Image with a Graphics object to keep track of the state of the window. |
In order to draw or write text to the window, you must override the paint method:
|
The Graphics object g has a current color and font that can be changed by methods |
The window system can be interrupted for various reasons - the user resized it or some other window was put on top of it and then removed - and it does not save a copy of the pixels. Instead it calls the paint method. So even if you only draw one window, paint can be called many times. |
Most applets and windows applications want to change what is drawn on the screen over its lifetime. This can be a sequenced animation, response to user input or mouse events, and so on. |
Whenever you want to redraw the screen, call
|
Repaint gets the graphics context g and creates a thread to call update(g), which calls your paint method. So all your drawing changes can also be put in paint. |
One draws a sequence of text and shapes to define the screen, where the position of the object in the screen is given by pixel coordinates. If one object overlaps another, the latest one drawn covers up the area of overlap.
|
Graphicsinstance.setFont(particularFont) will set the current Font in the instance Graphicsinstance of the Graphics class to the value particularFont of class Font. |
The class Font has an important constructor used as in |
Font MyFont = new Font("TimesRoman", Font.PLAIN ,36);
|
FontMetrics fm = getFontMetrics(particularFont); // allows one to find out about the font
|
Drawstring uses leftmost baseline point as (x,y) |
Nancy |
leading |
ascent |
descent |
baseline |
} |
height |
Color c = new Color (redvalue, greenvalue, bluevalue); red/green/bluevalue can be specified as integers in 0 ... 255 or floating point numbers from 0 to 1. |
c is generated as a Color in RGB format. |
graphicsobject.setColor(c); // sets current color in graphicsobject which is used for all subsequent operations |
There are particular Color instances already defined such as
|
Check out more examples
|
180 |
270 |
90 |
(See later for in-depth discussion of thread use) |
A thread is a single sequential flow of control within a process. |
If a process has more than one thread, then each thread executes concurrently. |
Any Java applet that has extensive execution or loops to repaint the window must run as a concurrent thread with the browser window. |
To make an applet with a thread:
|
These applet start and stop methods can always be used to start and stop the thread. |
import java.awt.*; |
import java.util.Date; |
public class DigitalClock extends java.applet.Applet |
implements Runnable |
{ Font theFont = new Font("TimesRoman", Font.BOLD, 24); |
Date theDate; |
Thread runner; |
public void start ( ) |
{ if (runner == null) |
{ runner = new Thread(this); runner.start ( ); } |
} |
public void stop ( ) |
{ if (runner != null) |
{ runner.stop ( ); runner = null; } |
} |
The body of the applet is in the run method, in this case a loop to keep showing the date. |
public void run ( ) |
{ while (true) |
{ theDate = new Date ( ); |
repaint ( ); |
try { Thread.sleep ( 1000); } |
catch ( InterruptedExecution e) { } |
} |
} |
public void paint ( Graphics g ) |
{ g.setFont ( theFont ); |
g.drawString ( theDate.toString ( ), 10, 50 ); |
} |
} |
We want to make applets that can have objects of different shape moving across the applet window.
|
We will design a hierarchy of classes to represent various shapes (including rectangles).
|
Applet |
mRectApplet |
variables: |
mPoint object[ ] |
methods: |
init |
run |
start |
stop |
update |
paint |
mPoint |
variables: |
int x, y, dx, dy |
Color color |
methods: |
setDelta |
setColor . . . |
move |
paint |
mRectangle |
int w, h |
paint |
checkBoundary . . . |
mOval |
paint |
mTriangle |
paint |
uses |
The Applet class provides a method getImage, which retrieves an image from a web server and creates an instance of the Image class. |
Image img =
|
Another form of getImage retrieves the image file relative to the directory of the HTML or the directory of the java code.
|
The Graphics class provides a method drawImage to actually display the image on the browser screen.
|
You can also scale the image to a particular width and height.
|
When drawImage is called, it draws only the pixels of the image that are already available. |
Then it creates a thread for the imageObserver. Whenever more of the image becomes available, it activates the method imageUpdate, which in turn call paint and drawImage, so that more of the image will show on the screen. |
The default imageUpdate doesn't work if you are double buffering the window in which the image appears. |
More control over showing the image as it downloads can be obtained by working with the MediaTracker class, using methods that tell you when the image has fully arrived.
|
This example shows how to get the actual height and width of the image to use in scaling the image under java program control. |
import java.awt.* |
public void class Drawleaf extends java.applet.Applet |
{ Image leafimg; |
public void init ( ) |
{ leafimg = getImage(getCodeBase( ),"images/Leaf.gif"); |
} |
public void paint ( Graphics g ) |
{ g.setFont ( theFont ); |
g.drawString ( theDate.toString ( ), 10, 50 ); |
} |
} |
Unless you are careful, dynamic applets will give flickering screens |
This is due to cycle
|
There are two ways to solve this problem which involve changing update() in different ways
|
This sets background color and initializes applet bounding rectangle to this color
|
Here you have two "graphics contexts" (frame buffers of the size of the applet), and you construct the next image for an animation "off-line" in the second frame buffer. |
This frame buffer is then directly copied to the main applet Graphics object without clearing image as in default update() |
In init(), you would create the frame buffer:
|
In paint(), one will construct applet image in offscreenGraphics as opposed to the argument g of paint(). So one would see statements such as:
|
Finally at end of paint(), one could transfer the off-screen image to g by
|
One would also need to override the update() method by
|
The DigitalClock doesn't flicker, but this illustrates the technique on a short example. |
public void class DigitalClock extends java.applet.Applet |
implements Runnable |
{ . . . |
Image offscreenImg; |
Graphics og; |
public void init ( ) |
{ offscreenImg = createImage (getSize( ).width, getSize( ).height); |
og = offscreenImg.getGraphics ( ); |
} |
public void paint ( Graphics g ) |
{ og.setFont ( theFont ); |
og.drawString ( theDate.toString ( ), 10, 50 ); |
g.drawImage ( offscreenImg, 0, 0, this); |
} |
public void update ( Graphics g) |
{ paint ( g); } |
} |
Components such as buttons, textfields, etc. |
Java 1.1 Event Model |
In Java, the GUI (Graphical User Interface) is built hierarchically in terms of Components -- one Component nested inside another starting with the smallest Buttons, including Menus, TextFields etc. and ending with full Window divided into Frames, MenuBars etc. |
The placement of components in the window is controlled in a fairly high-level way by one of several Layout Managers. |
The user can interact with the GUI on many of its components, by clicking a button, typing in text, etc. These actions cause an Event to be generated, which will be reported by the system to a class which is an Event Listener, and which will have an event handler method for that event. This method will provide the appropriate response to the user's action. |
Other components can be placed inside a container. |
Component |
Label |
Button |
Checkbox |
Scrollbar |
TextComponent |
TextArea |
Textfield |
ScrollPane |
List |
Canvas |
Container |
Panel |
Window |
Applet |
Dialog |
Frame |
For each basic component, one can create one or more instances of the component type and then use one of the "add" methods to place it into a Container such as an applet window. |
For now, we assume that components are added to the window in order from left to right and top to bottom as they fit. (This is actually the default FlowLayout Manager). |
Also for each component, there will be other methods:
|
This is an area where text can be displayed in the window. |
Create an instance of the Label class and add it to the window:
|
Another constructor allows a second argument which is an alignment: Label.LEFT, Label.CENTER, or Label.RIGHT
|
Method setText allows you to change the String in the Label, and getText() returns the current String
|
aligned left aligned right |
A Button is the familiar way to allow a user to cause an event and is created with a String to label it
|
Buttons are normally created to appear in the style of the user's windowing system, except that you can control the color of the button and the String
|
Click here |
An Event Listener is an instance of any class that wants to receive events. |
An event source is an object that generates events. An event source will keep a list of event listeners who want to be notified for particular events. |
The event source notifies event listeners by invoking a particular method of the event listener (aka the event handler method) and passing it an Event object, which has all the information about the event. |
For example, a component with a button is an event source, which generates an event called ActionEvent. There must be a class which implements an interface called ActionListener and which is on the list of listeners for that button. Then the Java system will provide the mechanism that passes the ActionEvent to a standard method of the ActionListener interface, namely a method called actionPerformed(). This method will receive the event object and carry out the response to the event. |
When the button is created, it should have at least one listener class added to its list of listeners:
|
where eventclass is an instance of the listener class.
|
Then this class must implement the interface ActionListener. This interface requires only one event handler method:
|
If the event source class is acting as its own listener, then you just say
|
Every event has a source object, obtained by getSource(), and a type value, obtained by getID(). In the case of buttons, the ID is ACTION_PERFORMED. Other Events may have more than one type of event ID. |
Event subclasses also have methods for whatever data is needed to handle the event. For example, ActionEvent has a method paramString() which for buttons, returns the string labelling the button. MouseEvent has methods getX() and getY(), which return the x and y pixel location of the mouse, and getClickCount(). |
AWTEvent |
ActionEvent |
InputEvent |
Adjustment |
Event |
ItemEvent |
ComponentEvent |
MouseEvent |
KeyEvent |
. . . |
To add a text field for display or input one line of text (in this case, 30 characters wide):
|
The text which is displayed can be changed:
|
If the user types input into the text field, it can be obtained:
|
Or you can disallow the user to type:
|
The TextArea class also has these methods, but it can display multiple lines. |
When the user types in text and presses "return" or "enter", an ActionEvent is generated, so, similarly to Buttons, an ActionListener must be provided. |
Checkboxes are on-off toggles implemented as
|
The first two are initially set to "false" as the optional third argument is not given. The last one is initially set to "true". |
The state of a checkbox, i.e. whether it is checked, is given by a boolean result of the method, getState:
|
If a user clicks a Checkbox, an ItemEvent is generated. The listener must implement ItemListener with the one method itemStateChanged (ItemEvent e). |
Red |
Green |
Blue |
Radio buttons are identical to Checkboxes but grouped so that only one checkbox in a group can be on at a time. They use same class for checkboxes, but add CheckboxGroup class.
|
In addition to checking the state of checkboxes in a group, there is a method to return the one checkbox which is on:
|
Choice is a class that gives a menu where you choose from various items, also sometimes called a drop-down list. Selecting an element of the menu generates an ItemEvent. |
List is another child of Component that is similar in use to Choice but gives a fixed size list which can be scrolled and where you can select one or more entries. Lists can generate both ItemEvents if the user selects (clicks once) an item, and ActionEvents if the user double-clicks an item. |
Scrollbar is a class that defines a horizontal or vertical scrollbar. Note this is distinct from scrollbars that come with TextArea and List. It generates AdjustmentEvents. The AdjustmentListener must have a method adjustmentValueChanged. |
More generally, any component, including containers, can generate mouse and keyboard events as the user moves or clicks the mouse in the window, or types a single key on the keyboard. |
This is most likely used in a Canvas or graphics drawing area. |
Typing a single key generates two KeyEvents. These events must be handled by implementing the KeyListener interface. It has three methods corresponding to the three actions that can occur on a key:
|
Typically, one uses methods to find the name of the key pressed or typed:
|
There are seven different MouseEvents, handled by methods in both the MouseListener and the MouseMotionListener interfaces.
|
We set up a test program that creates three movable objects, a rectangle, circle and triangle, as in the earlier example. In this program, we start with them all red. Whenever the mouse is detected to be over one of the objects, its color is changed to cyan. If the mouse button is used to drag the object, we move the object to the mouse location. |
Note that it is not necessary to introduce a thread for this applet since it is not running continuously - it is mostly waiting for mouse events. |
In designing classes for event handling, typically there is a class that defines the components where the response to the event is supposed to be performed. It is the most straightforward to make this class implement the listener for those events. |
In large applications, some Java experts recommend that it is a better design to always make the event listener class a separate class. They find that they can make event listener classes generic enough so that they can reuse a class such as
|
For every Event Listener interface with more than one method, there is a corresponding Event Adapter class. For example, there is an MouseAdapter class to go with the MouseListener interface. |
The adapter class implements its corresponding listener class by providing all of the required methods, but which have bodies that do nothing. |
For interfaces like MouseListener and MouseMotionListener, this can be handy because there are several methods in each interface. Typically, you don't want to implement all of the methods. So it is more convenient to make a class which extends the adapter class than to directly implement the listener class.
|
The various panels in a container are laid out separately in terms of their subcomponents |
One can lay components out "by hand" with positioning in pixel space |
However this is very difficult to make machine independent. Thus one tends to use general strategies which are embodied in 5 LayoutMangers which all implement the LayoutManager Interface. One can expect further custom LayoutManager's to become available on the Web |
To create a layout, such as FlowLayout, in your panel:
|
FlowLayout is a one dimensional layout where components are "flowed" into panel in order they were defined. When a row is full up, it is wrapped onto next row |
BorderLayout arranges the components into five areas called North, South, East, West and Center. |
GridLayout is a two dimensional layout where you define a N by M set of cells and again the components are assigned sequentially to cells starting at top left hand corner -- one component is in each cell. The cells are the same size. |
CardLayout lays out in time not space and each card (Displayed at one time) can be laid out with one of spatial layout schemes above |
GridBagLayout uses a class GridBagConstraints to customize positioning of individual components in one or more cells |
BorderLayout has five cells called North South East West Center and components are assigned to these cells with the add method. Unlike other add methods, here the order is not important:
|
Remember this is default for a Frame Container |
The constructor "new BorderLayout()" can have no arguments or "new BorderLayout(hgap, vgap)" can specify numbers of pixels inbetween components. |
North |
South |
W |
e |
s |
t |
E |
e |
s |
t |
This simple layout manager "flows" components into the window. The components can be aligned, and space between them specified by arguments hgap and vgap:
|
The FlowLayout Manager's strategy includes making each component its default "preferred size". |
The first two arguments of the GridLayout constructor specify the number of rows of cells (i.e. number of cells in the y direction) and the number of columns of cells (in the x direction)
|
Additional arguments hgap and vgap specify the number of pixels inbetween the columns and rows:
|
The GridLayout Manager's strategy is to make each cell exactly the same size so that rows and columns line up in a regular grid. |
Each component in a Layout may itself be a Panel with another Layout Manager, thus subdividing areas of the user interface. Using this hierarchy one can achieve complex GUI's. |
A simple example of using hierarchical Layout divides the main applet space into two components in a BorderLayout. The Center component is a Canvas for drawing graphics or images; the North component is itself a Panel which has three buttons in a GridLayout. This example is a very simple example of a standard paradigm for drawing or displaying data.
|
Canvas is a simple class that is used to draw on as in artist's canvas. They cannot contain other components. This is the class on which you use the graphics methods. |
Canvases can be included as parts of other Containers. In this case, you may need to obtain a Graphics object for drawing:
|
Up to now, we have described how to build typical Applet panels inside browser window. There are classes that allow one to generate complete windows separately from the browser window |
Window Class has subclasses Frame and Dialog |
Create a window with a given title:
|
A Frame has a set of classes to define MenuBars and Menus:
|
Several Menus, which each have menu items, can be added to the menubar:
|
Note that there are also CheckboxMenuItems, submenus,and (new) MenuShortcuts. |
Another type of separate window is the Dialog box, which is not so elaborate as a frame.
|
Dialog boxes are used for transient data
|
A ScrollPane provides a scrollable area within an existing window. It is a container which can have one other component added to it. This component may have a larger area that will be visible in the ScrollPane. For example, suppose that you have a Canvas drawing area that is 1000 by 1000 pixels wide. You can define a ScrollPane that will view part of it at one time.
|
A PopupMenu is a sometimes called a context-sensitive menu. On most systems, the right mouse button cause a popup trigger event, and you can create a PopupMenu to appear. |