![]() ![]() 16 August 2000 ![]() |
![]() |
Into Java, Part 8
Welcome back to this eighth installment of this Java column. I wouldn't
have mentioned how lovely Swedish summers can be since this summer seems to be one of the most rainy summers within
living memory. |
||||||||||||||||||||
The Event Model
As stated the previous month, every time we would like to use graphical
objects, like buttons, menus or alike, we will treat them as sources or originators of events. Java handles these
events by instantiating Event objects reflecting the action that took place. Clicking a button will cause an ActionEvent
to be created. And these actors will be built automatically by the Java environment. |
|
#include
)
anything, but import gives a shorthand to the many classes in the packages we are using, like java.awt, javax.swing
and others.There are three ways to get in touch with the classes of Java:
javax.swing.JButton butt = new javax.swing.JButton("MyButton");
import javax.swing.JButton;
...
JButton butt = new JButton("MyButton");
import javax.swing.*; // every class of the javax.swing package
...
JButton butt = new JButton("MyButton");
JLabel label = new JLabel("MyLabel"); // possible as well
double rand = java.lang.Math.random();
that gives us a random number. But more frequently we use the import mechanism
of Java to get to one class or several. What will happen then?Upon compiling, the import lines instructs the compiler where to
look for the classes we refer to and are using. The JDK compiler (javac) and most other, but not all, Java compilers
searches several possible directories to find the class we are referring to. Normally the compiler starts to search
the JDK environment, more exactly the classes.zip
located
by the CLASSPATH environment variable of your system. Within that zip-file the compiler tries possible directories
that the import statements implies, whether the directories exist or not. Then the compiler continues with every
possible path set by the CLASSPATH, like swingall.jar
and others. Finally the compiler concatenates the current directory (.
) with the import statements and tries
to find what it looks for.
The only package we never need to import is
java.lang
that is always searched, treated as the universal
package and the origin of all beings found in the community of Java.
In a future column we will discuss what exactly is a package, until
then we may know them as a group of classes, or a collection of classes. The personnel at SUN have neatly structured
the many classes in packages reflecting the purpose of the classes, i.e. java.io,
java.net
, etc. Whenever you start creating your splendid
Java tools yourself you may collect them into a directory that will be your package.
JFrame
, found in
javax.swing
. Hence we now have a class that we will
design ourselves, but to that it more formally speaking is a javax.swing.JFrame
, that is a java.awt.Frame
, that is a java.awt.Window
, etc.To that we add the promise of implementing the method(s) of the
interface ActionListener
.
Looking java.awt.event.ActionListener
up
we will find that only one method was asked for, namely public void actionPerformed(ActionEvent
e)
. So, later we will see to it and implement such a
method. If we distrust ourselves we might add the method right away as an empty method.
javax.swing.AbstractButton
that is kind of a superclass
of many GUI items. Today we will use another way of determining the event originator in the
actionPerformed
method. But the main reason why we declare
the buttons as variables is that we like to refer to them later on, hence we need a reference to them.We declare the image file names as variables as well. That will
mainly remind us of the good habit of grouping information that we may change later on among the variables. In
fact that will not increase the memory usage since only one object is made, but references to it are used. This
time we can assume that the image file names will change over time. Furthermore, never hesitate using these long
but descriptive variable names. In spite of the abundant typing you will save time from looking up those clever
but so-hard-to-remember abbreviations and acronyms people love to use.
|
Toolkit
?Class Toolkit
is found in java.awt
which implies that it is a class handling user interfaces, painting graphics or images.
The Java API tells us that "subclasses of Toolkit
are used to bind the various components to particular native toolkit implementations.
... The methods defined by Toolkit
are
the "glue" that joins the platform-independent classes... ." The purport of this is that a
toolkit acts as a channel, or "glue", to the system-dependent information we would like to
query or system-dependent resources we would like to use. Hence we get ourselves the reference
tk
that will give us access to the system you are running,
that may differ from your neighbor's system.
|
setLocation(20, 20)
. You never know
where that will be indeed. A better way is to first query the users screen resolution and then compute a good
place to put the application, if you do not use some kind of INI file, but then you are not likely reading this
Java column I presume <grin>.Class Dimension
simply encapsulates the width and height of a component (in integer precision)
in a single object. There is not much to tell about it except that it may only be used together with java.awt.Component
and its subclasses.
Not to forget that the width
and height
are public variables and hence
need no accessor methods, you query them directly as the code shows.
How to compute the position of a frame to put it at the middle
of a screen? As seen we subtract the size of the frame from the dimension of the screen and then halve the result.
(If your frame size is not known to you at this moment you may use the method public
Dimension getSize()
and maybe put these lines at the
end of the constructor.) Since we declared w
and h
as integers the result of the division
will always be truncated down to closest integer upon assigning them, that is one pixel at most.
For any possibility, test that w
and h
will
not be negative. Robust and sound code will always do such tests, how weird they may seem there is always a user
more weird anyway. Finally, we set the location of the frame with the now safe values.
|
tk
we
simply call the method getImage
with
the icon file name as a string parameter. Note that the image that Toolkit
can handle has to be of GIF or JPG file format, thus you need tools like
PMView to convert *.ICO files to the GIF or JPG file formats. Finally you
add the image as an icon to the frame.The latter part of the constructor is well known to us, we add
an adapter as a listener to the frame and override one of its empty methods. But the next line, what does it say?
We know the sense of the former part of the last line. But we have
added a call to a method, makeContent()
,
that seems to be added to the contents pane. Yes, that is correct! Usually we move out as much code as possible
from the constructor to make it more readable, and that code lifted out will be placed in a helper method such
as makeContent()
. This
technique is especially useful when there are plenty of panels and GUI components, each of these components may
be constructed in a method of its own. Another profit is that it will be a lot more easy to maintain and rebuild
the components.
Adding the panel at the "Center" will be discussed next
time, when we will look at layout managers. Until then you may try to change the "North" parameter used
the former month (FirstButtonFrame) to "Center" or the other cardinal points. As you noticed then the
background color did not fill the entire area of the frame. Why? What is the result if you change this parameter?
|
Toolkit
to
make ourselves images or icons. That is since we use a class found in javax.swing
that in fact uses the Toolkit
class behind the curtains. If you find it more convenient,
and you like to be spared from using the Toolkit
class,
you may instantiate an ImageIcon
and
then use the method public Image getImage()
,
i.e.
Image img = new IconImage("anImageFileName").getImage();
|
setHorizontalTextPosition(int textPosition)
,
where AbstractButton.LEFT, CENTER
or RIGHT
are valid parameters, i.e. leftButton.setHorizontalTextPosition(AbstractButton.LEFT)
.
And why not the accompanying method setVerticalTextPosition(int textPosition)
with AbstractButton.TOP, CENTER
or BOTTOM
as
valid parametersFinally we disable the right button, as the application
in use will show us why. Recall that false
is
a basic data type, a boolean. It is very common that only one method is used, such as
setEnabled
, with boolean
true
or false
sent as parameter. The opposite would be two methods, a
setEnabled()
and a setDisabled()
, which is more clumsy.
|
this
as a listener. So we do. The middle button, though, has the only purpose
of acting as kind of a light bulb, thus we do not add a listener to that button.A new touch is the convenient "flyover help" that will
guide new users of this splendid and complex application around.
|
Recall that this helper method was supposed to return a Container,
a superclass to many kind of graphical components used in a Java application. The signature of this method is private Container makeContent()
, hence
we have to return the panel we made. Such helper methods are, as said, commonly used and they more or less always
follow this style. Imagine this app having several such panels, how lengthy the constructor would become if no
helper methods are used, now only one line each container is necessary.
ActionListener
we have to add the method
beneath, that is the only method of the java.awt.event.ActionListener
interface. The method will get an event object as parameter and searches
it for who the event originator is. This time we use another approach, we try if the reference given by getSource
refer to the same object
as any of the buttons we made ourselves. Since references always points to objects (and in fact are closely related
to pointers, memory addresses) we may compare them directly, as in "is 'address of the event source' the
same as 'address of leftButton'?" The answer will decide which action is chosen.
|
|
This time we added a few gadgets to our tool box. But foremost
we once again went through the event source--event object--action listener model. Once we understand this model
it will be an easy task adding to an application's GUI. Helper methods were used and advocated and how the import
mechanism works were briefly discussed.
Next time we will use some more items from Swing, discuss some
OOP concepts that are essential to know about, have a look at layout managers, how they work and what shortcuts
there are and look at the Graphics class. Now I hope that the rain will stop and tomorrow will be a sunny day.
See you next month.
The ButtonDemo.java
and the javaimages.zip
Previous Article |
Next Article |