This network capability was shown in the HotJava World Wide Web browser, which would accept an extended form of HTML containing compiled Java programs (applets) and run those programs locally. This has since been adopted by other browsers such as Netscape. HotJava was, of course, entirely written in Java using the Java libraries.
Since then Java has been licensed to Borland and Microsoft among others, and the growth looks set to continue.
Why Java is of particular interest to readers of the X Advisor is in the AWT (Abstract Window Types) library that is used for the GUI components of HotJava and that can also be used for the GUI components of applets. The library is complete enough to both build fully functional standalone GUI applications, to perform drawings and show images and animations.
There are many tutorials on the Java language, and some books. The reader is referred to these for information on Java itself. Several of these also deal with applets, which use many (but not all) of the AWT toolkit.
This overview concentrates on using the AWT toolkit to build standalone
applications, and relates some of the implementation aspects back to X.
Later articles will deal in more detail with particular features of
the AWT toolkit, such as the Event
class,
geometry management, dialogs and extending the
toolkit with new widgets.
Component
are the basic building blocks for GUI
applications - what in Motif would be called the Primitive widgets
and other widgets such as Dialogs and Managers.
Pulldown menus are handled by a different hierarchy, subclasses
of MenuComponent
.
The Event
class defines the various types of event that can occur.
Since this is a library designed to work across multiple platforms, these
are not the familiar X Event types.
Geometry management is not built into Manager widgets like it is
in Motif/Xt.
Some Component classes allow objects to be placed within them.
Each of these ``Container'' classes has an associated Layout
object.
The various layout management schemes subclass from
Layout
, and implement geometry management.
In fact, the Manager classes of AWT are all implemented for X
using a Motif DrawingArea
, and the Layout
objects place visible
components within this.
Component
(except for Menu items).
It is still convenient to use this terminology though.
These classes include Button
, Checkbox
,
Label
,
List
, ScrollBar
, TextArea
(multi-line text) and
TextField
(single-line text).
There are a few Motif widgets missing from this: ArrowButton
,
DrawnButton
, Scale
and Separator
,
as well as the
newer widgets from Motif 2.0 such as SpinBox
.
In addition, the objects often have restrictions compared to the Motif
widgets. For example, Label
will only show a single-line label,
discarding everything after a newline character. There is also no means of
setting the direction of text display. None of the fancier effects that
are possible using Motif 2.0 RenderTables (such as multiple fonts and colours)
are possible. It is not possible to display a Bitmap/Pixmap instead of text.
While the AWT Label
is implemented using a Motif
Label
such aspects
of the Motif widget are either not accessible or are deliberately
turned off.
Nevertheless the set is large enough to be useful. The following figure
shows an AddressBook containing a
List
, three Label
's, two TextField
's
and a
TextArea
. Notice that the TextArea
shows both
its scrollbars,
even though they are not needed here. This behaviour is hard-coded into
the Motif implementation.
Layout
classes (this is sufficiently complex to require separate articles).
The AWT Container classes cover a wider range of behaviour:
Dialog
,
FileDialog
, Frame
, Panel
and
Window
.
Many Motif widgets such as SelectionBox
, and conveniences such
as WarningDialog
are missing from AWT. You have to build them
yourself.
Every standalone application requires at least one Frame
.
This is implemented for X by an ApplicationShell
plus a Motif
MainWindow
containing a DrawingArea
.
The MainWindow
allows a Pulldown menu to be attached, while other
objects can be placed in the DrawingArea
.
For internal organisation of objects into groups, a Panel
is
an AWT
general container.
A FileDialog
gives the familiar Motif FileDialog
(but modal only), while the Dialog
class is used to build other
dialogs.
Label
in a Frame
is
import java.awt.*; public class Hello extends Frame { public static void main(String argv[]) { new Hello(); } Hello() { Label hello = new Label("Hello World"); // bring it under geometry control add("Center", hello); resize(200, 200); // map the widgets show(); } }The static method
main()
creates a new object of class
Hello
,
that extends Frame
. A new Label
is created and then added
to the geometry control of the Hello
object.
The Layout
object responsible for geometry control is not visible here:
the Hello
object has a default Layout
object of class
BorderLayout
that is doing the management.
The "Center"
argument tells the
BorderLayout
object to use all
remaining space for the Label
.
For those interested in some implementation aspects:
when the AWT Label
is created using the new()
method,
the Motif Label
is not
yet created - it can't be, because the parent widget is not known.
However, when it is added to the Hello
object the parent is then
known and the Motif Label
widget can be created.
All widgets are created
Managed but Unmapped. The show()
method maps all the widgets.
postEvent()
for the object it occurred in.
For subclasses of Component
, this calls the
handleEvent()
method in the object.
If this returns false
,
it calls handleEvent()
in the parent object, etc, till either the
method returns true
or the top of the tree is reached.
Note that these events are not X events, but AWT events. They are triggered
by certain actions occurring in widgets, but not by all actions.
For example, when a Motif PushButton
is activated, an AWT event
with field id
set to ACTION_EVENT
is sent to the AWT Button
.
However, when the Motif PushButton
is merely armed, no AWT event is generated.
This often causes problems due to expectations from native GUI implementations:
for example, the TextArea
class is implemented using a Motif Text
widget. In Motif, callbacks can be added to XmNmodifyVerifyCallback
and
XmNmotionVerifyCallback
to track key and pointer events within the
widget. However, the AWT toolkit does not use these callbacks, so it is
impossible to track such actions within TextArea
.
Most AWT classes inherit the handleEvent()
method
from Component
(note: this does not include classes derived
from MenuComponent
). This does a switch on event id
and calls another method:
public boolean handleEvent(Event evt) { switch (evt.id) { case Event.MOUSE_ENTER: return mouseEnter(evt, evt.x, evt.y); case Event.MOUSE_EXIT: return mouseExit(evt, evt.x, evt.y); ... default: return false; } } public boolean mouseEnter(Event evt, int x, int y) { return false; }Not all events call methods: some fall through to the default case which returns
false
.
The methods called for AWT objects all return false
.
They can be overridden in a user-defined subclass.
For a concrete example of this, consider Button
. When the Motif
PushButton
is activated, an AWT event with id
set to
ACTION_EVENT
is generated. handleEvent()
calls the method
public boolean action(Event evt, Object what)
The second argument here is the value of the button's label as a String
.
To examine it, it will need to be coerced to this class.
If you use a Button
and wish to attach application code to the
callback, you do so by overriding action()
in a subclass
class MyButton extends Button { public boolean action(Event evt, Object what) { // handle button ... System.out.println("I've been pushed"); return true; } }(Note that you need to return
true
to prevent the event from being
passed to its parent.)
To give a realistic example of this, consider the problem of password
entry. The password should be entered into a
single-line TextField
.
This class actually has a special method to set the echo character to
something other than the input character (general access to more dynamic
modification might have been more useful, but never mind).
When the newline character is pressed, the method action()
is invoked.
Override this in a subclass of TextField
to get useful behaviour:
import java.awt.*; public class Password extends Frame { public static void main(String argv[]) { new Password(); } Password() { add("Center", new PasswordText()); resize(100, 20); show(); } } class PasswordText extends TextField { PasswordText() { setEchoCharacter('*'); } public boolean action(Event evt, Object what) { System.out.println(getText()); return true; } }
MenuComponent
(MenuBar
, Menu
,
MenuItem
, CheckboxMenuItem
).
Menus are pulldown menus only.
You can have pulldown menus only in a standalone application, not an
applet, because they need to be attached to a Frame
(unless the applet creates its own Frame
).
Menus can be changed by the setMenu()
of Frame
,
which unmaps the old menu and maps the new one.
A menu consists of a MenuBar
which
holds a set of Menu
objects.
Each element of a pulldown pane is a MenuItem
or
CheckboxMenuItem
(or subclasses),
and it is added to the appropriate Menu
object by the add()
method. Here is a simple menubar with one pulldown pane, which would be,
say, a private method of a subclass of Frame
:
private void CreateMenu() { MenuBar mb = new MenuBar(); Menu fileB = new Menu("File"); mb.add(fileB); MenuItem newB = new MenuItem("New"); MenuItem quitB = new MenuItem("Quit"); fileB.add(newB); fileB.add(quitB); setMenuBar(mb); }This creates a menubar with one item
File
. When this is selected
a menupane with items New
and Quit
is displayed.
Unfortunately, event handling within menus is not ideal.
It has been designed to be different to Component
,
which I find to be a nuisance.
When a MenuItem
is selected,
an event with id
set to
ACTION_EVENT
is generated and postEvent
is
executed for that object. However, this does not call handleEvent
like Component
objects do - there is no method
handleEvent
for MenuItem
s.
Instead it calls the postEvent
method for the parent in the
GUI tree. So it walks up the GUI tree till it gets to the ancestor
Frame
object, and will execute handleEvent
for the Frame
.
Because there is no handleEvent
method for
MenuComponent
objects, there are none of the convenience
methods to handle events such as action
or
mouseDown
.
I find this a poor approach because it requires that the
Frame
object
knows all sorts of detail information about the structure of its menu.
This will make the application difficult to change as it evolves.
It is quite easy to make menus behave in the same way as
Component
s, but means tampering with a method that the
designers of the AWT toolkit would probably prefer you not to: the
postEvent
method. This is really part of the implementation
side that normally should not be overridden.
However, that seems to be the simplest thing to do to get consistency
in event handling.
We have no interest in actions for MenuBar
and
Menu
- only in MenuItem
.
Define a new subclass of MenuItem
with two methods
postEvent
and action
. This shortcuts the
Component
mechanism that also uses the handleEvent
method.
class MenuButton extends MenuItem { public void postEvent(Event evt) { if (evt.id == Event.ACTION_EVENT) if (action(evt, evt.arg)) return; } super.postEvent(evt); } public boolean action(Event evt, Object what) { return false; } }
In future, subclass all menu buttons from MenuButton
,
with application logic in action()
class QuitButton extends MenuButton { public boolean action(Event evt, Object what) { System.out.println("Exiting..."); System.exit(0); return true; } }
As an example of this, let us look at a Label
in a
Frame
, where we can
change the foreground colour of the Label
by
selection from a Menu. The complete code for this is
import java.awt.*; public class ColorMenu extends Frame { private Label label; public static void main(String argv[]) { ColorMenu cm = new ColorMenu(); cm.show(); } ColorMenu() { label = new Label("Hello"); add("Center", label); CreateMenu(); resize(100, 100); } private void CreateMenu() { MenuBar mb = new MenuBar(); Menu fileB = new Menu("Color"); mb.add(fileB); ColorMenuButton blueB = new ColorMenuButton("Blue", this); ColorMenuButton redB = new ColorMenuButton("Red", this); fileB.add(blueB); fileB.add(redB); setMenuBar(mb); } public void changeColor(Color col) { label.setForeground(col); } } class MenuButton extends MenuItem { MenuButton(String name) { super(name); } public void postEvent(Event evt) { if (evt.id == Event.ACTION_EVENT) if (action(evt, evt.arg)) return; } super.postEvent(evt); } public boolean action(Event evt, Object what) { return false; } } class ColorMenuButton extends MenuButton { ColorMenu toplevel; ColorMenuButton(String name, ColorMenu top) { super(name); toplevel = top; } public boolean action(Event evt, Object what) { String name = (String) what; if (name.equals("Red")) toplevel.changeColor(Color.red); else toplevel.changeColor(Color.blue); return true; } }Let us look at selected parts of this code. The class
ColorMenu
is a toplevel Frame
extended to hold a label and a menu.
An additional method is used to set the color of the label.
MenuButton
derives from MenuItem
and adds the new postEvent
and action()
methods.
We also have to add in a constructor method that just
calls the super
constructor. We need to do this because MenuItem
has only one
constructor, which takes a String
parameter,
and such constructors cannot be inherited in Java.
The buttons we actually want in the menu are of class
ColorMenuButton
.
This derives from the MenuButton
class and
overrides the action()
method. In this, it calls the method changeColor
of the toplevel
ColorMenu
, which resets the foreground of its Label
.
The toplevel is passed through as a parameter in the constructor.
An alternative could be to walk up the parent tree when required till the
toplevel is reached.
The AWT model differs from the Motif/Xt model in many places, so forms a new API to be learnt, with its own vagaries. Some of these have been pointed out in this article. Further articles will deal in more detail with other aspects of the toolkit.
This article is based on a tutorial to be given at the X Technical Conference in February, 1996. The tutorial also discusses geometry management and adding new new widgets, among other things.
For other tutorials on the AWT library, see http://jan.newmarch.name/java/index.html , http://ugweb.cs.ualberta.ca/~nelson/java/AWT.Tutorial.html .
For information on Java books, see http://www.aw.com/cp/javaseries.html or http://www.digitalfocus.com/digitalfocus/faq/books.html .
The principal site for Java is the development site http://java.sun.com/ . This points to pages to download executables for Solaris, Windows NT and Windows 95. You can also get the source code, under certain conditions. An excellent Linux port of Java has been performed by Randy Chapman This is available from ftp://java.blacktown.org/pub/Java/linux