Multimedia with Java

Content

  1. Java Basics
  2. Java IDEs
  3. Java Plugin
  4. Object-Oriented Programming
  5. AWT containers and layouts
  6. Events
  7. Semantic Events
  8. Adapters
  9. Message Dialog
  10. Custom components in AWT
  11. Swing Overview
    1. Model-View-Controller
    2. Models for lists
    3. Tree models
    4. Actions
    5. Renderers
    6. Combobox - An Exercise in Design
    7. More complex example, more Swing (table, slider) and more on design
  12. Animations and Java2D
  13. Low-level Media Access: Playing Controlled Sound with JavaSound
  14. Custom Event Handling
  15. Generic Event Handling: OO Design "To Da Max"
  16. Sampled Sound - Decoding Format and Wave Display
  17. Responsive Swing Applications
  18. Playing Video with JMF
  19. Media in 3-D 
  20. Custom Look and Feel

Java Basics

Java in General

A Java program is written as a text file with extension .java, which Java compiler translates into bytecode file with extension .class. Bytecode is code for a virtual machine (VM). Bytecode is platform independent: you can compile on a Mac an transfer your *.class files to UNIX or a PC. Bytecode is interpreted by an interpreter (which defines the VM). Each browser has an interpreter. The interpreter loads *.class files and executes them.

Java Programs

There are two types of Java programs: As our software will be online, all our (and your) programs will be applets. (Later, we will look at a new technology called WebStart, that can run within a web browser and is therefore an alternative to applets.)

Classpath and File Structure

A classpath in java is a collection of folders (directories) from where the interpreter can find all class files. The codebase is the equivalent concept for applets running within a web browser. We recommend to organize your files as follows:
Each project has its own folder, within this folder is: If your Java classes are structured into packages (and they should be), then the structure of the folders within the /bin folder must correspond to the structure of your packages. (It's only natural to keep the same folder structure within your /src folder.) If you structure your files this way, then the codebase is ./bin (or simply bin).

To give an example, consider an applet jan.SampleGUI that imports a class jan.gui.Widget. Than the file structure should be:
  --- 465/
+--- sample_project/ project folder
+--- sample_gui.html web page displaying jan.SampleGUI
+--- src/ folder with sources
| +--- jan/ folder for package jan
| +--- SampleGUI.java
| +--- gui/ folder for package gui
| +--- Widget.java
+--- bin/ folder with classes = codebase, classpath
| +--- jan/ folder for package jan
| +--- SampleGUI.class
| +--- gui/ folder for package gui
| +--- Widget.class
+--- doc/ folder with documentation
+--- bak/ folder with backups

Java IDEs (Integrated Development Environments)

We recommend Eclipse - it's free and well established.

Some IDEs - offer a "GUI-designer" that allows you to develop the user interface (GUI - graphical user interface) of your software visually, e.g. select GUI elements from a palette and "drop" them within the area of your applet. Every time we drop a GUI widget into the applet the IDE inserts Java code into our source file.

Typically, the code a GUI-designer IDE will generate is pretty awful. Even the best IDE will not be able to produce very good, readable source code - that's the programmer's - e.g. your - job. Don't simply assume that no one will ever read such code because the GUI can be modified in a GUI-designer, use the designer tool to sketch out the GUI and then make all the necessary changes so that the code is great.


Java Plugin

When Java became popular, web browsers became equipped with the Java interpreter (aka Java Virtual Machine - JVM). Unfortunately, that meant that applets couldn't use the newest versions of JDK. Microsoft's Internet Explorer (IE), for instance, doesn't use Java anymore. The "Java Plugin" allows an applet to use the version of JDK that it needs, albeit at the cost of very long download time the first time an applet executes. The Java Plugin instructs the browser to look for a particular version of JDK and if it isn't found locally, to download it. (That's done automatically in IE, in Netscape Navigator the user must do it herself.) All our applets use Java Plugin with JDK version 1.5.

Originally, the web page that displayed an applet had to contain the following "applet tag":
  <applet 
      width      = "400"
      height     = "300" 
      code       = "edu.hawaii.ics.ami.gui.Demo" 
      codebase   = "bin"
archive = "ide.jar,lib.jar" parameter1 = "value1" parameter2 = "value2">
Please use a Java-enabled browser to view this page
</applet>

where edu.hawaii.ics.ami.gui.Demo is the qualified name of the applet's class and the text within the tag is displayed in browsers that don't support Java. (The codebase, archive and parameterN attributes are optional - archive lists all jar-archive files and parameterN are applet-specific arguments. We highlighted in color the parts that will vary from applet to applet. )

The web page needs to be converted into a form that initiates the Java Plugin processing.  We suggest that you use a template and simply edit it with a text editor. This is the template:

  <object
      width     = "400"
      height    = "300"
      codebase  = "http://java.sun.com/update/1.5/jinstall-1_5-windows-i586.cab#Version=1,5,0,0"
      classid   = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93">
    <param name = "code"        value = "edu.hawaii.ics.ami.gui.Demo" >
    <param name = "codebase"    value = "bin" >
    <param name = "archive"     value = "ide.jar,lib.jar" >
    <param name = "parameter1"  value = "value1" >
    <param name = "parameter2"  value = "value2" >
    <param name = "scriptable"  value = "false" >
    <param name = "type         value = "application/x-java-applet;version=1.5">
    <comment>
      <embed
          width       = "400"
          height      = "300"
          code        = "edu.hawaii.ics.ami.gui.Demo"
          codebase    = "bin"
          archive     = "ide.jar,lib.jar"
          parameter1  = "value1"
          parameter2  = "value2"
          scriptable  = "false"
          pluginspage = "http://java.sun.com/products/plugin/index.html#download"
          type        = "application/x-java-applet;version=1.5">
      </comment>
</embed>
</object>

Only the places highlighted in red are applet-specific and may need to be changed. (The <object> tag instructs IE to use JDK 1.5 and download and install it if necessary; the <embed> tag is used in Navigator and directs the reader to the plugin page if download is needed.) Note that the download will take quite long time - but once the user has the JDK installed, the applets start executing immediately - well, at least the classes start loading immediately.

One word more regarding applets: The applet parameters, such as parameter1 in the above example, allow you to parameterize your applets, i.e. make it independent on some values that are defined in the applet's web page. This allows you to have, for instance, several web pages with different applet parameters that rely on the same code, or change the behavior of your applet without changing your applet's code.


Object-Oriented Programming: Review and Example

This course requires a firm grasp of the concepts of object-oriented programming (OOP) and their practical application: inheritance, polymorphism, abstraction. Concretely, you need to be - or to quickly become - familiar with such basic Java constructs as subclasses that extend superclasses, classes that implement interfaces, and abstract classes that call abstract methods.You need to know how to handle exceptions. All these features are used extensively in the Graphical User Interface frameworks that we will be using.

Arguably the single most important concept in OOP is that of a class - you can't write a Java program without it. Yes, you can write a completely procedural, Pascal-like (or C-like) program and put it into class MyPride {...} around it but unless it's a very simple program, you probably shouldn't be too proud of it. Your program deals with objects and each object must have a class that defines what the object is composed of (fields or instance variables) and what it can do (methods). Unless you deal only with objects with predefined classes (e.g. those in JDK), you should define a class for each type of object and use objects of these types in your program. If your program consists of just one class that means that you maintain that there is only one object that you deal with!

The second most important concept of OOP is abstraction and inheritance, i.e. that of a subclass that extends a superclass. The subclass inherits all the functionality of the superclass it extends, i.e. all its fields and all its methods. In Java, a subclass can extend only one superclass - there is no multiple inheritance as in C++. (The class does actually inherit the functionality of multiple classes - those of it's immediate superclass, this superclass' superclass, etc. all the way to the root of the class hierarchy, the class java.lang.Object. The term "no multiple inheritance" just means "no inheritance from multiple immediate superclasses.")

A subclass can override a method it inherits, i.e. define its own implementation of the method. If you then call this method with an object of the subclass, the overriding code is executed. (This is called polymorphism.) Example:

class HawaiiHi {
  String greet () {return "Aloha! ";}
  String thank () {return "Mahalo! ";}
}
class CasualHi extends HawaiiHi {
  String greet () {return "Howzit brah! ";}
}
class Test {
  public static void main (String dummy []) {
    HawaiiHi hi = null;
    hi = new HawaiiHi ();
    System.out.println (hi.greet () + hi.thank ());
    hi = new CasualHi ();
    System.out.println (hi.greet () + hi.thank ());
  }
}

This program will write to the output console:

Aloha! Mahalo!
Howzit brah! Mahalo!

Notice that even though we declared hi as an object of class HawaiiHi, we got two different results when we called hi.greet(). That's because we assigned hi to become an object of the subclass CasualHi that redefined (overrode) the method greet() from HawaiiHi.

The overriding methods must have exactly the same signature, i.e. the same name, the same return type and the same types of parameters - only the parameter names play no role. You have to be careful, if just the type of one parameter is different, e.g. long instead of int, or just one letter in the method's name is lowercase instead of uppercase you didn't override the methods but declared a new one and the methods gets never called - such bugs are hard to find.

Now you probably think that the above example is just an academic exercise and the software architecture of our program is too complicated. Yes, to make the example more explanatory we let both types HawaiiHi and CasualHi "thank" using the same word but "greet" differently. Moreover, you could write the two lines with only two statements. But our code correctly expresses that while there is a common way to thank, there is a normal greeting in Hawai`i that every one, even tourists, understands and a special type of greeting that the "locals" in Hawai`i may use if they greet another local. The subclass - superclass relation with overriding just expresses that a local greeting knows "betta" how to greet. (I translate it for the non-locals: "it knows a better version.") But there is an even more compelling argument than just the logical correspondence to the real world. Suppose that we would like to improve my code and ban the System.out.println statement into its own method. (You'll notice that code that is perfect is our code while the code that needs improvement is mine.) This will not only look better, but is a good software engineering practice because we need to change the code only in one place if we want to print the greeting somewhere else then to the console.

class Test {
  void print (HawaiiHi hi) {System.out.println (hi.greet () + hi.thank ());}
  public static void main (String dummy []) {
    print (new HawaiiHi ());
    print (new CasualHi ());
  }
}

Now you should see clearly the advantage of the declaring CasualHi as subclass of HawaiiHi - the method print() can accept any object of type HawaiiHi or one of its subclasses, such as CasualHi. Similarly, we could declare an array of objects of one type and fill it not only with objects of this type but also with objects of one of the subclasses of the type, e.g.:

class Test {
  HawaiiHi hi_s [] = {new HawaiiHi (), new CasualHi ()};
  void print (HawaiiHi hi) {System.out.println (hi.greet () + hi.thank ());}
  public static void main (String dummy []) {
    for (int i = 0; i < hi_s.length; i++) {print (hi_s []);}
  }
}

Did you notice that all the above program variants produce the same output?

An interface in Java defines methods that have to be defined in every class that implements the interface. The interface itself defines only the signatures of the methods. In other words, a method within an interface can't have a body. You can declare variable with an interface type. Let's change the above code to use an interface:

interface Hi {
  String greet ();
  String thank ();
}
class HawaiiHi implements Hi {
  public String greet () {return "Aloha! ";}
  public String thank () {return "Mahalo! ";}
}
class CasualHi extends HawaiiHi {
  public String greet () {return "Howzit brah! ";}
}
class Test {
  void print (Hi hi) {System.out.println (hi.greet () + hi.thank ());}
  public static void main (String dummy []) {
    print (new HawaiiHi ());
    print (new CasualHi ());
  }
}

The class HawaiiHi implements interface Hi. The class CasualHi is subclass of HawaiiHi. It also implements the interface because its superclass does. (We could state it in the code but we don't need to - it's a good practice, however, to state it because it makes the code more readable.) The parameter hi in print() has now the interface type Hi. As you can see, we can pass either an object of the superclass HawaiiHi or an object of the subclass CasualHi. Let's try to explain the software architecture in layman's terms again: There may be lots of greetings, if they obey the "contract" defined by interface Hi, print() knows how to print them. The greetings of type HawaiiHi obey the contract and so do CasualHi greetings because they are just a specialized type of HawaiiHi greetings. (Observe that parameter passing is just an implicit assignment of the actual parameter to the formal parameter, so an assignment of a CasualHi or HawaiiHi object to variable Hi - such as in Hi hi=new CasualHi() - is perfectly legal.)

Let's stress the main point again - the beauty of this code is that we can use the method greet() with an object of a type (the interface Hi) that defines only the method's signature. The method print() needs only to know what is the signature of greet(), not how its body is implemented. Instead of creating the new concrete objects whose class implements greet() directly, the main program could receive them via remote method invocation (RMI) or instantiate then from dynamically loaded classes based on names the user types in. Even though in both cases the main program doesn't have the faintest idea what is the actual type of the object, its print() method can do it's job! In other words, as long as the parameter object hi fulfills the contract Hi, print() will print it.

This is a very powerful concept - we can define a set of interfaces in between two software layers and while one team of programmers is busy writing classes that implement them, another team can write the software layer that uses these interfaces. Of course, the teams will have to specify more details of what the methods are supposed to do, but as far as Java is concerned, the signatures are all what is needed to let the teams write and compile their layers independently.

Now let's return to our last program. (Did we point out that it produces the same output in the console as the previous ones?) Let's modify it slightly to use an abstract class instead of the interface:

abstract class Hi {
  public abstract String greet ();
  public abstract String thank ();
}
class HawaiiHi extends Hi {
  public String greet () {return "Aloha! ";}
  public String thank () {return "Mahalo! ";}
}
class CasualHi extends HawaiiHi {
  public String greet () {return "Howzit brah! ";}
}

The only syntactical differences are that Hi is an abstract class that HawaiiHi extends and that the method greet () is also declared as abstract. In particular, notice that the abstract methods has only signature and no body, exactly as it was within an interface. But there are more than syntactical differences, the most important one is that HawaiiHi cannot extend another superclass. (This is in contrast to the previous example where HawaiiHi was implementing the interface Hi and we were free to let it extend another superclass - there is no limit on number of interfaces a class can implement.) Compare this with the following alternative to the program that uses the interface:

interface Hi {
  String greet ();
  String thank ();
}
class HawaiiHi extends Component implements Hi {
  public String greet () {return "Aloha! ";}
  public String thank () {return "Mahalo! ";}
  public void paint (Graphic canvas) {canvas.drawString (0, 20, greet ());}
}
class CasualHi extends HawaiiHi {
  public String greet () {return "Howzit brah! ";}
}

As we will see later, an object of type HawaiiHi - and due to inheritance also an object of type CasualHi - is now a visual component that can be displayed within a Java window on the screen. And due to polymorphism, a HawaiiHi component displays the string "Aloha! ", but a CasualHi displays "Howzit brah! ". This is because both types of component are displayed by "painting" the result of greet() on the screen and the overridden greet() is executed for a CasualHi component.

But if an interface gives more flexibility than an abstract class, why do we even need the concept of an abstract class? Lets now look at the main program - it declares the method print() and then calls it twice with different object parameters. Obviously both types of objects can be "printed". In our code - sorry, my code - the main program needs to "know" how to print them. But since it's a functionality common to all greetings, wouldn't it be better is the object "knew" how to be printed? Let's start with the simplified main program:

abstract class Hi {...}
class HawaiiHi extends Hi {...}
class CasualHi extends HawaiiHi {...}
class Test {
  public static void main (String dummy []) {
    Hi hi = new HawaiiHi ();
    hi.print ();
    hi = new CasualHi ();
    hi.print ();
  }
}

You may now think: That's not much simpler! But consider that we can rewrite the code (the changes are purely syntactical, the semantic remains the same):

abstract class Hi {...}
class HawaiiHi extends Hi {...}
class CasualHi extends HawaiiHi {...}
class Test {
  public static void main (String dummy []) {
    new HawaiiHi ().print ();
    new CasualHi ().print ();
  }
}

This looks better, doesn't it? Ok, now let's tackle the classes. Obviously, the method print() must be within the abstract superclass Hi because it's called with a variable hi that has type Hi in the longer version of the main program. We could make print() abstract, i.e. implement it in the subclasses. But print() depends only on greet() and greet() is defined in Hi already. If we can use an abstract method outside of the class, we can certainly use it within the class itself, too. Let us then implement print() directly:

abstract class Hi {
  public abstract String greet ();
  public abstract String thank ();
  public void print () {System.out.println (greet () + hi.thank ());}
}
class HawaiiHi extends Hi {...}
class CasualHi extends HawaiiHi {...}
class Test {
  public static void main (String dummy []) {
    new HawaiiHi ().print ();
    new CasualHi ().print ();
  }
}

As you can see, moving print() from the main program to the class Hi improved our code. Our objects became more functional and as a side benefit our code became shorter and also more readable - in other words, more elegant.

As we have seen, both concepts - interfaces and abstract classes - have their advantages and disadvantages: An abstract class can have a mixture of abstract methods and methods with fully implemented bodies, but prevents subclasses from inheriting features of other classes. Interface, on the other hand, declares only methods signatures, but an implementing class is free to choose its superclass. The natural question is: Can we have the best of both worlds? The answer is: Almost. We can define an interface and an abstract superclass class that declares (some) of the methods defined in the interface. This abstract superclass typically implements some of the methods and leaves the others abstract, to be implemented in the concrete subclass. We expand our example to demonstrate it:

interface Hi {
  String greet ();
  String thank ();
  void print ();
}
abstract class HiComponent extends Component implements Hi {
  public abstract String greet ();
  public abstract String thank ();
  public void print () {repaint ();}
  public void paint (Graphic canvas) {canvas.drawString (0, 20, greet () + thank ());}
}
class HawaiiHi extends HiComponent {...}
class CasualHi extends HawaiiHi {...}
class Test {
  public static void main (String dummy []) {
    Hi hi = new HawaiiHi ();
    hi.print ();
    hi = new CasualHi ();
    hi.print ();
  }
}

We didn't eliminate the no-multiple-inheritance problem completely - we'll need an additional abstract superclass if need to inherit the functionality of another class, but this is as far as Java lets us spread our wings.

The applet greetings demonstrates the above code.

We'll finish this section with an example that applies the above theory to a very concrete and useful application. Consider the task of drawing the graph of a function y=f(x). Look at the following web pages: sin, cos, tan, x_to_3.They all display the same applet, albeit with different applet parameters. Since the applet can draw different functions - it can in fact draw arbitrary functions provided that they follow a "contract" - one of the applet's parameters must define the function itself. The applet then somehow plots the function's graph. How did we achieve this magic?

Let's start with a sketch of the algorithm that draws the function's graph. This algorithm is always the same for any function: We start with x1' at the left edge of the drawing area, convert it to x1 in the real domain, compute y1=f(x2), then convert y1 to y1' of the drawing area. Then we increment x2' = x1'+1 and find y2'. Now that we have two points (x1',y1') and (x2',y2') we draw a line in between. We continue till the point (xN',yN') where xN' is at the right edge of the drawing area. This is the algorithm in Java:

      double scale = area.width / (xTo - xFrom);
      int yAxis = area.height / 2;
      // compute point on the left edge
      int x1 = 0;
int y1 = yAxis - (int) Math.round ((function.f (xFrom)) * scale);
for (int x2 = 1; x2 < area.width; x1++, x2++) {
// convert screen x to x in the domain of real numbers
double x = x2 / scale + xFrom;
// convert y=f(x) from real numbers to screen y
int y2 = yAxis - (int) Math.round (function.f (x) * scale);
// draw connecting line from previous point to new one
canvas.drawLine (x1, y1, x2, y2);
// remember last point
y1 = y2;
} // draw the function's name in top left corner canvas.drawString ("y=" + function.name (), 5, 20);

The algorithm assumes that the size of the drawing area extends from (0,0) to (area.width,area.height) and that we want to draw the function in between xFrom and xTo. For simplicity sake it also assumes that the x-axis runs through the center of the drawing area and unit length is the same in both dimensions. Notice that we need to mirror the y coordinate on the y-axis because the y coordinates on the screen start at the top edge and extend downwards which is the opposite direction than what the users are accustomed from their math lessons.

The rest is simple. We'll first define an interface for functions that the above algorithm can draw:

interface Function {
  public double f (double x);
  public String name ();
}

For most of the common functions it's a trivial task to implement the corresponding class. For example y=sin(x) will be represented by the following class:

public class Sinus implements Function {
  public double f (double x) {return Math.sin (x);}
  public String name () {return "sin(x)";}
}

To make it really obvious that our program does not need to know the actual type of a function object let's read the name of the name of the class, load the class and instantiate it, i.e. construct an object whose type is this class:

    try {// to load function dynamically
      Function function = (Function) Class.forName (className).newInstance ();
    } catch (Exception error) {...}

This neat trick is called "dynamic class loading." We pass the className to the static method forName() within the class Class. It loads the class that we are interested in and returns an object that represents this class. This object helps us to instantiate the class, i.e. a call to its newInstance() method creates an object of our newly loaded class and returns it. Now that we have the actual Function object - at least we assume it fulfills our Function contract - we can draw its graph. This assumption is reflected in the type cast - if it's wrong Java throws a ClassCastException which we need to catch in the try clause. Needless to say that both forName() and newInstance() can cause other exceptions, for instance if the class file can't be found, if it contains garbage, or if an exception occurs within the constructor. We can handle these exceptions summarily, because we read the class name from the applet's parameter and can resolve the problems before we publish the applets.

Notice that we could easily let the users type in the class name. With a little more effort we could even let them type in a URL of a class file they developed on their own computer! (Of course, we would need to provide a much better error handling.)

These are the source files and the zip archive with all files:

In object-oriented programming, lot of emphasis in the design of your software is on the relations between classes, objects and interfaces rather than on the structuring of the methods (as it was the case in "procedural" programming). Therefore there is a need to depict such complex relations graphically. The currently most popular standard in such graphical modeling is the Universal Modeling Language (UML). In particular, the UML "class diagrams" are the most commonly used means for representing the interrelations of a software system.

Using UML, the above system can be depicted as the following class diagram:


AWT containers and layouts

The GUI components can be hierarchically structure - they form a "component" tree. The inner nodes of this tree are "containers" - they can contain other GUI containers and components. The most common container is a "panel", i.e. an object of type java.awt.Panel.

Each of the containers is associated with a "layout". A layout object governs how the components (nested containers are components, too) are positioned within the container. AWT defines several layouts - the following applet uses the BorderLayout, FlowLayout and GridLayout layouts:

And this is the source of the applet and the zip archive with all files:

Quite a complicated hierarchy of containers and components is often necessary to achieve a specific arrangement of components on the screen. The above applet, for instance, has the following component hierarchy:

  +---Panels applet (a container with BorderLayout)
     +---north: label "ICS 465 is fun"
     +---west: vertical scrollbar
     +---center: center panel (with BorderLayout)
     |  +---north: checkbox panel (with GridLayout 2 rows * 2 columns)
     |  |  +---grid cell 1, 1: "true" checkbox (cell 1, 1 of the grid) 
     |  |  +---grid cell 1, 2: "I agree" checkbox (cell 1, 2 of the grid)
     |  |  +---grid cell 2, 1: "false" checkbox (cell 2, 1 of the grid)
     |  +---center: text panel (with GridLayout 1 row * 2 columns)
     |     +---text field (cell 1, 1 of the grid)
     |     +---text area (cell 1, 2 of the grid)
     +---south: panel (with GridLayout 1 row * 3 columns)
        +---grid cell 1, 1: panel (with FlowLayout)
        |  +---"OK" button
        +---grid cell 1, 2: choice
        +---grid cell 1, 3: list

Notice that the components at the leaves of the component tree have different depths (the scrollbar is at depth 1, the choice at depth 2, the "OK" button at depth 3) which does not always correspond to the intuitive visual hierarchy of the components. The GridBagLayout (see later) is much more flexible (and much more complex layout) that can simplify (i.e. flatten) the component hierarchy.

Instead of using a Panel, your program can also define is own containers simply be extending the class java.awt.Container, e.g.:

  class MyContainer extends Container {}

Unlike Panel, such a container is transparent. If you need just one transparent container variable, you can define the class directly within the variable's declaration:

  Container myContainer = new Container () {};

This declaration defines an inner "anonymous" class (We'll discuss inner and anonymous classes in more detail in our treatment of events).

There is only a very little use for a transparent component, but if we wanted one, we could declare it in similar fashion:

  Component myComponent = new Component () {};

The classes java.awt.Container and java.awt.Component are abstract and since we can't instantiate an abstract class, we have to implement a subclass, even if we don't need to define any additional functionality. There is no reason why these classes should be abstract, it's simply one of the (less) annoying design flaws in AWT - probably an oversight based on legacy considerations.


Demonstrations of layouts

The following applets have two purposes - they:
  1. visualize how the functionality of the standard layouts (except GridBagLayout).
  2. their implementation demonstrates the use of numerous GUI components and how to handle the associated events (see later).

These are the applets:

And these are the sources of the applets and the zip archive for the project:

As you can see all the layouts support horizontal and vertical gaps, however they differ in their interpretation what constitutes a gap: For BorderLayout and GridLayout the gaps are only in between the components, there is no distance to the edges of the container (well, not quite - GridLayout will leave out spare pixels at the bottom and on the right). For CardLayout, the gaps are the distance to the edges. FlowLayout uses the gaps not only in between the components, but also to determine the distance to the edges: the vertical gap is also the distance to the top edge while the bottom edge is completely ignored; the distance to the left and right edges is about 1/2 of the horizontal gap. FlowLayout is also the only layout where the default gaps are not 0.

Notice how some layouts are designed to expand (or shrink) the size of one or more components while other give the components their preferred size. (Even though some layouts define methods designed to support minimum and maximum sizes, the actual support within the implementations is poor to non-existent.) While GridLayout and CardLayout expand all components, BorderLayout expands the component in the center. BorderLayout gives all other components their preferred size as does FlowLayout with all the components.

A careful arrangement of nested containers can produce a wide range of desired layouts. There is a trick that my help you to achieve the visual impact that you want:


Events

The construction and arrangement of GUI components is one side of the user interface. The other side is the implementation of the functionality that these components represent. Some basic functionality is already provided - the text editing in a text field, the scrolling in a text area. Some simple functionality is provided by associating components together, such as associating checkboxes with the same CheckboxGroup to give them the appearance of radio buttons. (In AWT, this is slightly different in Swing.)

However, the most important functionality - e.g. what to do when the use clicks a button, selects an item from a list of from a menu - must be implemented by the programmer. Such user's interactions with the GUI components are represented as "events." Within an interactive program, the events are essentially method calls - or, more accurately, method "callbacks," because the runtime-system will call one of the event handling methods whenever the user interacts with a GUI component. The event handling methods are grouped into "listener" interfaces according to the type of interaction. For instance, the ActionListener interface corresponds to clicking a button, typing <enter> in a text field, or selecting a menu item. The WindowListener interface corresponds to the interactions with a Window, such as closing or minimizing it.

To receive event callbacks, the program must:

  1. provide an object the implements the particular XxxListener interface, and
  2. register this object with the GUI component using the addXxxListener() method.

In the simple case, a subclass of java.awt.Component can itself implement the listener interface and register its own instance (i.e. this) with the GUI component. For instance, our class BorderLayoutDemo defines a button setButton, implements the ActionListener interface and registers its own instance with the button with the statement setButton.addActionListener (this), in effect saying: I know how to handle the events my button generates , i.e. it's mouse clicks. This applet's actionPerformed() method will be then called whenever the user clicks the button. Similarly, this class also defines the checkbox checkbox implements the ItemListener interface and registers its own instance as the listener of the events it the user generates. (In effect saying: I will deal with checking and unchecking the the myself checkbox.) It's method itemStateChanged() will be called when a the user clicks the checkbox. (Notice that the visual appearance is handled automatically - you as a programmer don't need to worry about showing the check mark inside the box.)


Adapters

Most listener interfaces define several event-handling methods. To give an example the WindowListener interface has seven methods that correspond to window-specific user interactions, such as opening or closing a window. Typically you are interested only in the user's request to close the window. (You have to close the window yourself because, among other reasons, the runtime system does not whether you want just to hide it or to destroy it and its resources. You could even pop up a dialog box giving the user the choice to save some data, discard it or cancel, and, if the user chooses to cancel the close operation, leave the window opened.) But mostly you are interested only in the windowClosing() method - but what should you do about the other methods that the interface defines? You have to implement them, but no one can prevent you from just leaving their bodies empty. They will be called, but nothing will happen beyond the standard window behavior.

Can we avoid the six empty methods in our code? Yes, if the empty methods are somewhere else, e.g. in a superclass. So conveniently each of the XxxListener class with more than one method has an associated XxxAdapter class that implements all the methods in the interface but leaves their bodies empty. Now you can simply extend the adapter class and override only those methods that you need to. (As every time when you need to override a "callback" method make sure that you make no mistake in the method's signature - if its name or the type of one of its parameter is different, you have declared a new method which will be never called and the compiler will not complain!) If you are using Eclipse you can use the command Source->Override/Implement Methods... that will assure that the signature(s) are correct.

Inner and anonymous classes

It is often convenient to handle user events inside a method defined within the applet's class (or another GUI component) as we have done it in all previous examples. But such a class cannot extend an adapter in addition to extending the Applet class (or another AWT component, because Java does not permit multiple inheritance. Fortunately there is another way how to keep the listener code within a class' code - the inner classes. In the subsequent sections we will define a MessageDialog class that handles a GUI widget that is sorely missed in AWT. Such a dialog box is often used to display error or other information messages. To meet the standard functionality the users are accustomed to, the dialog box needs to display an "OK" button that dismisses the dialog. On GUI platforms that display a dialog box as a standard window with a "close box" within the window's title bar, the user expects that clicking this "close box" also dismisses the dialog box. Suppose that our class needs to handle closing the window automatically. But because there are two ways to close a message dialog and we want one object to handle closing the window, we can define the inner class Janitor to handle the user's request to close the dialog's window:

  class MessageDialog extends Dialog {
    Button okButton = new Button ("OK");
    public MessageDialog (...) {...
      Janitor janitor = new Janitor ();
      okButton.addActionListener (janitor);
      addWindowListener (janitor);
    }
    class Janitor extends WindowAdapter implements ActionListener {
      public void windowClosing (...)   {dispose ();}
      public void actionPerformed (...) {dispose ();}
    }
  }
Notice that the inner class Janitor calls the dispose() method without referring to an object, e.g. it is equivalent to the call this.dispose(). The reserved word this means "this object" or more precisely "this object of this class." But there are now two (lexically nested) classes and therefore two this objects. Fortunately the compiler can figure it out because dispose() is defined only for one of the "this" objects. This is very convenient - all the fields and methods of the outer class are available directly to the inner class! Consider the alternative code without an inner class:
  class MessageDialog extends Dialog {
    Button okButton = new Button ("OK");
    public MessageDialog (...) {...
      Janitor janitor = new Janitor (this);
      okButton.addActionListener (janitor);
      addWindowListener (janitor);
    }
  }
  class Janitor extends WindowAdapter implements ActionListener {
    Window window; // needed to call windowClosing()
    // constructor must be passed a window and remember it
    public Janitor (Window window) {this.window = window;}
    public void windowClosing (...)   {window.dispose ();}
    public void actionPerformed (...) {window.dispose ();}
  }
We can, however, simplify our original code even further using "anonymous classes," i.e. classes declared in place of an actual parameter (or within the declaration of a variable). Such a class doesn't need a name because it's declared using the reserved word new followed the name of a class or an interface. This determines which is the class that the anonymous class extends or which is the interface that it implements. Our code snippet becomes:
  class MessageDialog extends Dialog {
    public MessageDialog (...) {...
      okButton.addActionListener (new ActionListener () {
        public void actionPerformed (...) {dispose ();}
      });
      addWindowListener (new WindowAdapter () {
        public void windowClosing (...) {dispose ();}
      });
    }
  }
A word of caution: the anonymous classes can become very unreadable. The good programming style is to keep the body of each method within an anonymous class very simple, such as just a call of one method. If your code requires numerous statement, you should declare a separate (private) method, e.g.:
  class Class_ extends SuperClass {
    public Class_ (...) {
      registerCallback (new CallbackInterface () {
	     public void handleEvent (...) {complexMethod ();}
	   });
    }  
    private void complexMethod () {
      // numerous statements
    }
  }

Semantic events

The natural question is: How do I know which events a GUI component sends? The answer is quite simple for Java's AWT components. (And only a bit more complicated for the Swing components.) You look for an addXxxListener() method in the component's API documentation. This method has a XxxListener parameter and that's the interface that defines the events. Well, it's a little bit more complicated after all - you have to look for addXxxListener() methods in all the superclasses, too. The Dialog component, for instance, has eight listener interfaces associated with it:

  1. WindowListener (7 methods) due to addWindowListener() in java.awt.Window,
  2. ContainerListener (2 methods) due to addContainerListener() in java.awt.Container,
  3. ComponentListener (4 methods) due to addComponentListener() in java.awt.Component,
  4. FocusListener (2 methods) due to addFocusListener() in java.awt.Component,
  5. InputMethodListener (2 methods) due to addInputMethodListener() in java.awt.Component,
  6. KeyListener (3 methods) due to addKeyListener() in java.awt.Component,
  7. MouseListener (5 methods) due to addMouseListener() in java.awt.Component,
  8. MouseMotionListener (2 methods) due to addMouseMotionListener() in java.awt.Component
  9. HierarchyListener (1 method) due to addHierarchyListener() in java.awt.Component
  10. HierarchyBoundsListener (2 methods) due to addHierarchyBoundsListener() in java.awt.Component
  11. PropertyChangeListener (1 method) due to addPropertyChangeListener() in java.awt.Component
As you can see, a window can receive potentially up to 31 different kinds of events!

Some of the above interfaces correspond to basic interaction of the user with the computer hardware, such as typing a key on the keyboard, moving the mouse or depressing or releasing a mouse button (e.g. KeyListener, MouseMotionListener, MouseListener). Such events are translated into "higher level" or "semantic" events that interpret a sequence of basic events as one event with a more specific meaning. To give an example, the events of depressing a mouse button within the area of a Choice component, moving the mouse within the list of the choice's items and releasing the mouse button on one of the items will result in the callback of itemStateChanged() in all listeners of type ItemChangeListener registered with the choice. (Notice that you can receive callbacks for the semantic event as well as for all the basic events that it is "composed" of.)


Message dialog

There are two other standard containers in AWT besides a panel and a container. Both of these containers represent a window: a Dialog and a Frame. While a Dialog can be used to display modal and non-modal dialog boxes, a Frame is a window that can have menus. (A dialog is modal if the user can access only its components until she closes it.) Since Dialog and Frame have common functionality - their window has a titlebar, can be moved or resized, and maintains the standard window-specific buttons in the title bar (e.g. close, minimize, and maximize buttons), they inherit the common features from a common superclass Window. This is the class hierarchy of AWT most important components:
  +---Object
     +---Component
        +---Container 
        |  +---Window
        |  |  +---Dialog
        |  |  +---Frame
        |  +---Panel
        |     +---Applet
        +---Button
        +---Checkbox
        +---TextField
        +---TextArea
        +---List
        +---Choice
Notice that the class hierarchy is pretty much the opposite of the actual GUI hierarchy of component objects established by a Java program, such as the tree which we have seen in the previous section. In the actual GUI hierarchy a Window parent may contain a Container child that in turn can contain a Component as a child. In contrast, the parent superclass Component has a child subclass Container because a container is a component that has the additional functionality of being able to contain several other components. And Container itself is the parent superclass of Window parent because a window is a container that can be displayed separately on the screen and has such decorations as a tile bar. Subclasses add functionality, therefore the root to the GUI class hierarchy is the generic class Component and all other classes for GUI widgets are derived from it.

Let us now define a very useful class that AWT lacks. Typically, if an application wants to display a message in a dialog box - e.g. an error message - it needs more functionality than the standard Dialog provides, e.g. needs to display a dialog box with a message and an "OK" button. We define such a dialog within the class MessageDialog and show it's functionality in the applet dialog.

The implementation of MessageDialog isn't as straightforward as we may hope. One reason is that we'd like to display messages with more than just one line. The other two have to do with one of the most anoying quirks in AWT.

Let's deal with the latter problem first, as it is a good exercise in software design and shows that even seasoned software developers such as the autors of Java APIs at Sun can make some grave design mistakes. Naturally, in our first design MessageDialog will extend Dialog - after all it's a dialog with specific content. But since all Dialog constructors require an "owner" - another Dialog or a Frame - as a parameter, our constructor(s) must also have such a parameter - unless, of course, we can comew up with some acceptable value:

public class MessageDialog extends Dialog {
  public MessageDialog (String title, String message, Frame owner) {
    super (owner, title, true);
  }
}

My first hunch was that the dialog will be positioned in relation to the owner or the owner receives the focus when the dialog is closed, but it doesn't work this way. The documentation doesn't explain the parameter at all, so I had to look into the source files to find out that when the owner is hidden or disposed of all the owned windows are hidden or disposed of as well. More importantly, a Dialog can me "modal" i.e. it doesn't allow the users to access (e.g. close) the owner window. So it makes sense that AWT needs to keep track of the owner. (I didn't have patience to dig in the JDK sources to confirm that it's indeed done this way). What doesn't make much sense is to require every - even non-modal dialogs to provide an owner within a constructor. Logically, the owner should be provided as a parameter to setModal(). Hiding such a design flaw by lack of documentation doesn't makes things better. More annoying is that this parameter cannot be null so the programmers are stuck with having to provide some "reasonable" value here. While a visual standalone application needs a frame at the root of its GUI, it's not obvious how an applet should obtain such a reasonable frame value - certainly java.applet.* package doesn't gives us any clue. But as a seasoned Java programmer you can probably guess how to get to the requisite frame - it's one of the ancestors of the applet in the GUI hierarchy and we can simply go up in the tree until we hit an object of type Frame. We'd like to encapsulate the search for the "owner" within MessageDialog because 1) it doesn't make sense that everyone implements the same code, and 2) we would like to shield the application programmers from this nuisance. Of course, since such a method has uses for other dialogs, we can either 1) define a class ModalDialog that extends Dialog and shields its subclasses such as MessageDialog from the search for the owner frame, or 2) implement a utility class that provides getOwnerFrame(). Let's sketch the latter option - the method may come handy in other contexts:

  public static Frame getOwnerFrame (Component component) {
while (component != null) {
component = component.getParent ();
if (component instanceof Frame) {return (Frame) component;}
}
return null;
} }

I provided this method in the class edu.hawaii.ics.ami.awt.Utilities - notice that the package name indicates that I'm trying to extend the functionality of the java.awt.* package.

Now the constructor of our MessageDialog class can be implemented as follows:

public class MessageDialog extends Dialog {
  public MessageDialog (String title, String message, Component component) {
    super (Utilities.getOwnerFrame (component), title, true);
  }
}

and the programs that need to create a new MessageDialog need to provide only an arbitrary component.

Unfortunatelly, this is not all what we need to do to deal with this problem. The program that wants to create a new instance of MessageDialog still needs to provide a component parameter that can be used to find the owner. The catch is that this component must be already within the GUI hierarchy, i.e. it must have been already added to a parent Container that is within the GUI hierarchy, which itself must have been already added, etc., etc. Typically I like to instantiate objects when I declare them and that means that my instance variables (aka fields) are instantiates at the time when my components are created. As a consequence, my components could not have been added to the GUI hierarchy yet. For instance, the following code will not work:

class MessageButton extends Button {
  private MessageDialog dialog = new MessageDialog (title, message, this);
}

So how do you write your own component classes that shield the programs from falling into such tricky traps? I show this on the example MessageButton, a class that provides a button that displays our dialog box with a given message. This class uses a trick that is useful to know: When an AWT component is being added to the GUI hierarchy, its method addNotify() is being called. (This name is a good example of how NOT to call your methods - you should call your methods and classes based on WHAT they do, not HOW they do it - i.e. how they are implemented, and the WHAT should not be an exercise in obfuscation.) So how can you detect when addNotify() is being called? You override addNotify() and within the method's body you call super.addNotify(). Then you insert your own code:

class MessageButton extends Button {
  private MessageDialog dialog;
  public void addNotify () {
    super.addNotify ();
    dialog = new MessageDialog (title, message, this);
  }
}

The entire MessageButton class now became quite complex because we need to store the title and message text in instance variables so that they can be used in addNotify():

class MessageButton extends Button implements ActionListener {
  private MessageDialog dialog;
  private String title;
  private String message;


  public MessageButton (String label, String title, String message) {
    super (label);
    this.title = title;
    this.message = message;
    addActionListener (this);
  }
  
  public void addNotify () {
    super.addNotify ();
    dialog = new MessageDialog (title, message, this);
  }
  
  public void actionPerformed (ActionEvent event) {dialog.showDialog ();}
}

Can we simplify this code? Since my MessageButton is an inner class of the ShowDialog applet, there is a surprisingly simpler solution, provided that we take advantage of inner classes and know some tricks inherent to Java syntax:

public class ShowDialog extends Applet {
  ...
  class MessageButton_ extends Button {
    MessageButton_ (String label, String title, String message) {
      super (label);
      final MessageDialog dialog = new MessageDialog 
          (title, message, ShowDialog.this);
      addActionListener (new ActionListener () {
        public void actionPerformed (ActionEvent event) {dialog.showDialog ();}
      });
    }
  }
}

The key to the simplification is that we know that at the time when the ShowDialog applet is created, is is already part of the GUI hierarchy. In other words, we can use this as the component needed to find the "owner" Frame. These are the two syntax "tricks" that we further need:

  1. Within an inner class, there are several known this objects: in addition to this of the inner class there is also this of the enclosing class(es). To distinguish between these objects, we can prepend the class name of the enclosing class(es). In our case, ShowDialog.this is the current applet.
  2. Our anonymous class - the one that is subclass of ActionListener - needs to use the local variable dialog. This is permissible if we declare such variable as final. (Note that method parameters are also treated as local variables, so you can use this trick with parameters as well - simply declare them as final within the parameter list.)

Now let's not forget the other problem that our MessageDialog needs to solve - we want to display several lines of text. This problem is comparatively simple. We quickly abandon the option of using a TextArea to display the message because it doesn't look right and is misleading - an AWT TextArea has scrollbar(s) and since it supports editing of text, it maintains a caret and/or can highlight a selection within the text, even if its made "non-editable". The users will interpret it's specific "look" as: "I can edit the text in the area." and that's not we want them to think when they see a message dialog. Unfortunately, there is no other standard component that we can use. Label is the closest candidate, but it can display only one line of text. So what we do? We simply use several labels - and there is a layout that arranges them just in the right way - a GridLayout with one column. The only missing piece of the puzzle is how to split the message string into lines. The convenience method split() in java.lang.String does the trick - it splits a String into an array of Strings along any delimiter pattern. The sketch of the following method relies on the existence of the instance variable messagePane that uses a GridLayout:

  public void setText (String text) {
// remove previous labels
messagePane.removeAll ();
// split text into lines along the end-of-line delimiter
String lines = text.split ("\n");
// let the layout display as many rows as there are lines in text
((GridLayout) messagePane.getLayout ()).setRows (lines.length);
// create and insert labels for each line
for (String line : lines) {
messagePane.add (new Label (line));
}
}

Notice that we used the for-each construct that has been introduced in Java 5. Normally it's a convenient way to iterate through a collection, such as java.util.ArrayList. But it can be also used to iterate through an array. This is a very good example of consistent design, after all, an array also represents a collection of objects.

These are the sources of the dialog applet and the zip archive with all files:


Custom components in AWT

A there is no AWT component that can display an image, we had to implement our own custom component in the above applet. A custom component usually extends java.awt.Canvas (if it's transparent it extends java.awt.Component). It must override the method paint(Graphics) - that's where the component can draw the picture to appear on the screen into the Graphics context it obtained as a parameter. The details of painting process are quite intricate - a repaint manager may put together several requests to repaint() the component and then calls the component's update() which first fills the component's area with the background color and then calls its paint() method. These details are quite well explained in the article Painting in AWT and Swing. As a rule of thumb you should never call paint() directly, only repaint(). If you are sure that your component fills the component's area entirely, you can override update() and call there paint() directly:

  public void update (Graphics easel) {paint (easel);}

(Don't put all your drawing code into update() because under certain circumstances AWT calls paint() directly if it determines that update() isn't needed.)

Your custom component will automatically post all the basic events supported by the java.awt.Component class, but you can implement your own semantic events.


Swing Overview

The Swing framework is an implementation of a rich GUI developed in Java - the appearance of widgets', for instance, is drawn using Java graphical primitives. This is in stark contrast to AWT which uses the GUI widgets - buttons, menus, etc. - of the native operating system.) To give you some impression of the effort in writing the Swing's code consider that over 5MB of the byte code in JDK is dedicated to Swing - that's almost 1/4 of the entire basic JDK (22,9MB).

Swing offers all the features found in AWT (consult the SwingSet applet which comes with your JDK - you'll find it at \demo\jfc\SwingSet2\SwingSet2.html) and improves on AWT in numerous aspects:

On the downside, the complexity of Swing's APIs is intimidating - it's harder to figure out what features to use and how.

Let's single out a few specific advantages of Swing:

There are some basic differences between AWT and Swing:

Sometimes it becomes obvious that Swing design suffers from the fact that Swing had to be implemented on top of AWT. For instance, JApplet can't be a subclass of JComponent, because it must extend java.awt.Applet (it needs to inherit all the Applet's functionality. (In contrast, Applet is a subclass of Component in AWT.)

A detailed explanation of all Swing components goes beyound the scope of this lecture - Swing is used as an example of a GUI framework here. Please consult, for instance, this tutorial or the short course on the Sun's web site.


Model-View-Controller

The Swing GUI widgets are constructed using the Model-View-Controller (MVC) software design pattern. This pattern subdivides the functionality of a widget in to three components:

When the user interacts with the widget the Controller interprets the interaction - it often has to ask the View what part of the widget was affected and the Model what's the widget's state. Than it instructs the View to change the state. Typically, the Model must let the the View know how the state changed, so that View can give the user visual feedback that reflects the new state.

Because the Controller is must often have an intimate knowledge of how the widget is displayed, Swing combines the View and Controller and calls it UI (for User Interface). The models are, however, are kept separate - they are represented by interfaces that are called XxxModel. Each of these interfaces define methods that provide access to the widget's state.

The MVC design pattern has one obvious benefit - the model can be easily replaced. But there is another more practical advantage: the model can compute the widget's state rather than use an explicit data structure.

A complex widget can have several models, e.g. the data it visualizes and the selection state.

Models for lists

To make this abstract concept more concrete, let's examine a simple example. AWT supports two widgets that allow the user to choose from a list of items - List and Choice. Swing supports these widgets with the classes JList and JCombobox. (JComboBox functions as a choice, where the user can choose item from a pulldown list, but you can request an extended form that gives the user also the option to type in some text.) In AWT, you have no other choice than to fill the list of items using either add() or addItem(). Swing also supports addItem() in JComboBox, and allows you to initialize a JList with a Vector and than add() your items to the Vector. (This apparent inconsistency in Swing's design has little practical consequences.)

But Swing's models provide a more flexible alternative - you can develop a class that implements ListModel and provide JList with an instance of this class. Similarly we can provide JComboBox an object whose class implements ComboBoxModel interface. Since ComboBoxModel is subinterface of ListModel, we have to implement all the methods in ListModel in either case. The only two methods in ListModel we need to worry about are getSize() and getElementAt(index). This is not very surprising - these are the list-traversal methods that JList and JComboBox need to display all the items in the list. Swing doesn't care how these methods are implemented. For instance, if we have all the items in an array our code will look something like:

  public int getSize () {return array.length;}

  public Object getElementAt (int index) {return array [index];}

Or, if the items are within a java.util.List we can write:

  public int getSize () {return list.size ();}

  public Object getElementAt (int index) {return list.get (index);}

Notice that the return type of getSize() is Object, not String as you may have expected. Using Object is often more convenient, we simply need to know that the Object's toString() method is used to display the item.

Now let's use some magic - we don't need any the underlying data structure at all! We can compute the items on the fly, e.g.:

  public int getSize () {return 5;}

  public Object getElementAt (int index) {return index * index + "");}

This will display the first 10 squares as the items of our JList or JComboBox, i.e. 0, 1, 4, 9 and 16.

Now let us briefly outline why we don't have to worry about the other methods the interfaces prescribe. Because the implementation of these methods is standard, Swing provides us with classes that provide a default implementation - AbstractListModel and DefaultComboBoxModel. The classes for our models can simply extend these classes.

To give you a concrete example, I developed two applets that both compute the list items within the models' access methods. The loan_calculator applet uses JList to display a list of typical interest rates to compute the monthly payments for a loan with certain principal - i.e. loan amount - that has to be repaid over a certain number of years. The model's traversal methods are:

  public int getSize () {return count;}

  public Object getElementAt (int index) {return (from + index * step) + "%";}

This is the source and the zip archive with all files:

The color chooser applet is more elaborate and more useful. While colors are often defined in terms of their red, green and blue components (RGB), it's often visually more intuitive to choose a color based to its hue, saturation and brightness (HSB). (Every color has a unique representation in the RGB space and in the HSB space and there is a fairly simple formula for conversion from one space to the other.) This applet lets the user select the HSB coordinates with three JLists - one for hue, another for saturation and yet another for brightness. Since the hues are defined using numbers between 0 and 1 and the primary colors are at 0 (red), 1/3 (green), and 2/3 (blue) it's more convenient to display the lists items as fractions. The applet does therefore some fancy footwork in the models' access methods:

  class FractionsListModel extends AbstractListModel {

    int count = 20;
    int lastIndex = count - 1;
    int index;

    public FractionsListModel (int count) {
      this.count = count;
      lastIndex = count - 1;
    }

    public int getSize () {return count;}

    public Object getElementAt (int index) {
      if (index == 0) {return "0";}
      if (index == lastIndex) {return "1";}
      int gcd = gcd (index, lastIndex);
      return index / gcd + "/" + lastIndex / gcd;
    }

    private int gcd (int smaller, int larger) {...}
	
  }

This is the source and the zip archive with all files:

Caveat: Swing offers a very elaborate JColorChooser widget whose functionality goes well beyond our color chooser.


Tree models

The JTree widget is a one of the most complex Swing components. It displays a tree in a Window-Explorer-like fashion.

The most often used way to get a tree visualized with JTree is to build it from "default" nodes that JTree understands. The objects that should be displayed as the nodes are then attached to each "default" node as "user objects". (The colors_tree applet demonstrates how to do this as well as how to customize the display of a node using a "renderer".)

These are the sources and the zip archive with all files:

This approach, however, is quite wasteful if you have already a tree built from nodes of another type. But thanks to the MCV pattern we need only to let JTree know how to traverse our tree, i.e. implement an interface that JTree understands. This TreeModel interface, of course, only prescribes which traversal methods must be implemented and it's up to us to implement them. In an extreme case we don't need to have a tree at all! The colors_tree_model applet demonstrates how the JTree can be coerced into believing that we have an infinitely deep tree! It uses only five objects and lets JTree believe that each of them - when considered as a parent - has all of these objects as children. Notice that each object is therefore its own child (and consequently also its own parent)!

Note that our tree model can extend javax.swing.tree.DefaultTreeModel that provides the implementation of all the methods in the interface - we must only implement the tree traversal methods getRoot(), getChild(parent) and getChildCount(parent,index) as well as isLeaf(node) and getIndexOfChild(parent,child). Of course, the latter two methods can be implemented using the former ones! This is the code of our infinite tree model:

  class InfiniteTreeModel extends DefaultTreeModel {

    public InfiniteTreeModel () {
      // since the superclass insists on a DefaultMutableTreeNode, use a dummy
      super (new DefaultMutableTreeNode ());
    }

    public Object getRoot () {return items [0];}

    public Object getChild (Object parent, int index) {return items [index];}

    public int getChildCount (Object parent) {return items.length;}

    public boolean isLeaf (Object node) {return false;} // infinite tree has no leaves!

    public int getIndexOfChild (Object parent, Object child) {
      for (int i = 0; i < items.length; i++) {
        if (child == items [i]) {return i;}
      }
      assert false; // must not be reached
      return -1;    //to placate the compiler
    }

  }

Note that our model relies on an array items defined in the outer class. The acess methods simulate a tree where all parent nodes have the same sequence of child nodes.

These are the sources and the zip archive with all files:

Sometimes the tree that you want to display already exists and you can simply map the access methods of the source tree to the access methods of required by TreeModel. The tree of GUI components is such an example. The access methods to the GUI tree are getComponentCount() and getComponent(index) within the class java.awt.Container. The applet gui_tree displays the GUI hierarchys either that of the applet itself or of the additional frame with toolbar. Switching between the two trees is accomplished using actions that are added to the menu as well as to the toolbar.

This is how the tree traversal methods are implemented:

class GuiTreeModel extends DefaultTreeModel {

  Object root;

  public GuiTreeModel (Object root) {
    super (new DefaultMutableTreeNode (root)); //dummy root to placate the superclass
    this.root = root;
  }

  public Object getRoot () {return root;}

  public Object getChild (Object container, int index) {
    return ((Container) container).getComponent (index);
  }

  public int getChildCount (Object container) {
    return ((Container) container).getComponentCount ();
  }

  public boolean isLeaf (Object component) {
    return getChildCount (component) == 0;
  }

  public int getIndexOfChild (Object parent, Object child) {
    int n = getChildCount (parent);
    for (int i = 0; i < n; i++) {
      if (child == getChild (parent, i)) {return i;}
    }
    return -1; // should not happen
  }
}

Note:

This is the source file and the zip archive with all files:


Actions

In a simple interactive project, we can get away with creating our GUI widgets and associating them directly with the appropriate event listeners who then implement the corresponding actions. In a more complex project, it is often more convenient to separate these actions and disassociate them even further them from the corresponding widgets. In a sense, the action becomes the developer's main concern while the GUI widget becomes secondary byproduct that only represents the action to the user. As a consequence, there may even be several representations of the same action, such as a button and a menu item. Such GUI widgets that are associated with the same action can then share its properties. For instance, a good user interface design mandates that a GUI widget is disabled if the corresponding action does not make sense in the current context. Such disabled widget is typically grayed out and doesn't respond to user's clicks. To give an example, after the user saved her document in a test editor, the "Save" menu item should be disabled and remain so until she edited the document again. This gives the user the feedback and reassurance that her work is safely preserved on the hard disk. Now suppose that there is not only the "Save" menu item but also a "Save" button in a toolbar. Of course, as a user you expect that the "Save" button is disabled and enabled whenever the "Save" menu item is disabled or enabled. Similarly, you expect that other properties, e.g. the "tool tip", are shared as well.

Java Swing supports this separation of concerns between an action and its representation as GUI widget(s). It supplies the interface Action and the abstract class AbstractAction that implements Action - the developer then constructs subclasses of AbstractAction that represent the concrete actions of their interactive applications. The key is to this pattern is the method actionPerformed() - it has to be overridden and contains the code that executes the action. Using an anonymous class, the pattern is as follows:

Action myAction = new AbstractAction ("Label") {
  public void actionPerformed (ActionEvent event) {myAction ();}
};

myAction () {
  // execute the action
}

This code defines an anonymous class and constructs a new myAction object of this class in the process passing the String parameter "Label" to the constructor of AbstractAction. You may be wondering what is the purpose of this parameter. This parameter will be used when we create the GUI widgets that represent our action. This is the place where the usefulness of this software pattern becomes obvious - we don't need to construct the a menu item and then add it to a menu. Instead, we can simply add myAction directly to the menu and a menu item "Label" will be created automatically for us! Similarly, if we add myAction directly to a JToolBar, a button "Label" will populate the toolbar. This is a great example for good design - the developer is encouraged to use a concept that enhances the separation of concerns - the actions and their representation as GUI widgets - and is rewarded by simplifying her code. As a further benefit, it is sufficient to disable the action itself and all the widgets that represent the action will be disabled.

There are some rough edges in the Swing's implementation of actions. For instance, you can store the tool tip associated with an action but it will not be displayed. Moreover, you can add an action only to a menu or a toolbar, so if you want to use a button within your panels, you have to create a dummy toolbar, add your action to it and then extract the button from the toolbar. Despite these nuisances the concept is very valuable on its own right and the glitches can be easily repaired - you can, for instance, implement a subclass of AbstractAction that remedies the shortcommings.

Our gui_tree applet also demonstrates the use of the Action software pattern. It defines two actions and adds both to a menu and to a toolbar. It also enables and disables the actions (and thus the menu items and buttons) as appropriate.


Renderers

Several of the more complex GUI widgets support another advanced concept in GUI frameworks - the "renderer". A renderer is an object that is used to paint- often repeatedly - a part of the widget. For instance, a list displays numerous items, a tree displays numerous nodes and a table numerous cells. A renderer allows us to define a custom way to paint each item, node or cell. Typically we use an existing GUI widget as a renderer - a good choice may be a JLabel because it supports text as well as icons. But no one prevents us from defining a complex panel with a border and several inner widgets as a renderer. Or we can use a custom component as a renderer. Also, we usually use a single component as a renderer. However, we can define several widgets, e.g. one for the display of inner nodes in a tree and for the display of leaves, for instance in in order to make the display faster.

Our renderers are typically defined as a class that implements a renderer interface. We then create a new renderer object and pass it to the setXxxRenderer() method of our complex GUI widget. To satisfy the contract stipulated by the XxxRenderer interface, we need to implement one method that returns the renderer widget. This method will be then called whenever the complex widget needs to display one of its items. For instance, the JTree widget goes through all the nodes of the tree it needs to display, and gets the renderer for every single one of the nodes. When it figures out where a node needs to be displayed, it (re)positions the renderer correctly and paints it. Then it repeats the process with the next node.

The method that our renderer class implements features numerous parameters. These parameters inform us about the state of the complex widget. The most important parameter is Object value - this is the item to be rendered. Obviously, this is the object that was provided by our model, so you know that is its type and can cast it to the type that is convenient and extract all the information you need. Other parameters are of limited importance - for instance you may want to render an item that is currently selected in differently from an item that is not selected. Most other parameters are, however, seldom used.

We have seen already a custom renderer in the colors_tree_model applet - it allowed us to display each tree node using both an icon and a label. Let us now improve on the color_chooser applet that let the user choose the hue, saturation and brightness of a color from a list of fractions. The applet color_chooser_renderer is another variant of such HSB color chooser. Instead of fractions, this time I'm using the colors directly. Each list displays the current colors and all its variations in its dimension of the HSB color space. For instance, the list of hues displays all the colors that have the same saturation and brightness as the current color and varying hue. Similarly, the list of saturations keeps the current hue and brightness and varies the saturation. This is more visually obvious and pleasing way to choose a color. My custom renderer displays a swatch of a color in a JPanel. (There are couple of fine intricacies in the code, for instance the appropriate choice of color for the border that surrounds the current selection.)

These are sources of the color_chooser_renderer applet and the zip archive with all the files:


Combobox - An Exercise in Design

Combobox is an often used GUI widget that allows the user to either select one of the item from a pull-down menu - as a "choice" in AWT - or type in a value. In other words, combobox combines a choice with a text field. Swing supports the combobox widget, and allows the developer to define her own combobox model. However, the design choices and the implementation details are not as straightforward as you may expect. For instance, you could expect that since the data items in the combobox are displayed in a list-like fashion, the corresponding model would be identical to that of a list GUI widget, i.e. ListModel as for JList. But you have to implement ComboBoxModel which is a subinterface of ListModel. The Swing's documentation states that ComboBoxModel "... adds the concept of a selected item. ... This disjoint behavior allows for the temporary storage and retrieval of a selected item in the model." It is not quite obvious why a this is necessary or advantageous, and - if it is advantageous, why it is not advantageous for the ListModel as well. After all, other more complex widgets have besides their regular model also an additional "selection" model that manages the currently selected item(s). Fortunately, there is an abstract class that supplies the default desired implementation to the additional methods.

In addition, the event handling has to be implemented in a very specific way if we need to distinguish whether the user choose an item from the list or typed a new item. Such need arises often, e.g. if we want to include the new value in the list of choices. (After all, we don't want to force the user to type a value more than once.) Experimentation reveals that we can test if event.getActionCommand().equals("comboBoxChanged") within our ActionListener. If there is a simpler way, it certainly is not well documented. This is again a good lesson in software design - if you adapt a non-obvious and obtuse concept, you will have the inclination to "hide" it, i.e. omit it from any documentation. Avoid this trap by all means - your documentation must focus on the complex, difficult concepts and carefully explain them. (You can omit, however, the details of the obvious and expected concepts.) Of course, the best way to spend your time to invest it in careful design - then your concepts will be obvious and you can save the time documenting them.

In my combobox applet, I revisit the theme of displaying images and playing sounds. This time, I use Swing and combo boxes for the selection of images and sounds. Now the user can also type a URL link an display an arbitrary image or play an arbitrary sound. (Because of security restriction, you'll have to use a URL of an image or sound on your hard drive or tweak your permission so that my applet can connect to the web site where the resource is located.) Once the user enters a resource the combo boxes will add it to their list so that they can be easily selected again.

The implementation of this applet is also interesting because of its software architecture. The implementation of the original image_sound applet managed the images and sounds separately. That seemed to be justified because we display an image and play a sound in fundamentally different ways. However, a lot of the original code was identical. The better OOP design mandates that we declare an abstract class that contains the common code and use abstract methods to "hide" the differences. Then we implement these differences within the concrete subclasses. In our case, the abstract class Resource contains the common code and its concrete subclasses Picture and Sound implement the differences. The abstract method act() is implemented in Picture to display the Image and in Sound to play the AudioClip. As a side benefit, we can define a common ResourcesComboBox class to handle both types of resources.

This applet also demonstrates how to construct component that does its own a custom painting in Swing. Instead of overriding paint(Graphics) as in AWT, a custom component should override paintComponent(Graphics). The first statement in paintComponent(Graphics) must be a call to the superclass:

public void paintComponent (Graphics easel) {
  // Swing components must ensure that Swing can do it's painting job.
  super.paintComponent (easel);
  // ... custom painting
}

If you experience weird visual effects, you may have forgotten this requirement.. (You should also consider "insets" within your paintComponent() because Swing paints the borders there - e.g. the same way as our CustomComponent does it.)

These are the source file and the zip archive with all the files:

The next incarnation of the same theme is the applet combo_model. The only difference to the above applet is that the combo boxes use our own models. This is convenient because the natural way to collect our resources is within an ArrayList collection. (ArrayList is essentially an array that can expand as we add more elements to it.) Now such an ArrayList collection can easily serve as the data structure for a ListModel or a ComboBoxModel. We can easily implement the required access methods of the model with the corresponding methods supplied by the collection:

abstract class ResourcesComboBox extends JComboBox {

  ArrayList resources = new ArrayList ();
	
  ResourcesComboBox () {
    setModel (new ResourcesComboBoxModel ());
  }
	
  class ResourcesComboBoxModel extends DefaultComboBoxModel {
 
    public int getSize () {return resources.size ();}
 
    public Object getElementAt (int index) {return resources.get (index);}
  }

}

(Notice that the inner class ResourcesComboBoxModel can conveniently access the field resources in the outer class.)

I made another improvement in this incarnation of our applet - a class that ensures that a Swing component that performs ist custom painting obides by Swing's rules. This is the politically correct thing to do (or at least OOP-correct) - such class can be reused in other projects that necessitate custom components thus ensuring that they work "out of the box". Implementation note: the methods paintComponent() and paint() have been declared final to make sure that none of the subclasses interfere with the painting process.

This is the source file and a zip archive with all the files:


More complex example, more Swing (table, slider) and more on design

To round up our exploration of Swing, let's look at an applet that is more sophisticated in its appearance and functionality. Therefore we'll take advantage of two other of more advanced Swing components - JTable and JSlider. As always, we define our own models. And we also try remedy some of the design quirks of Swing.

Our sample color_chooser_table applet revisits the theme of choosing a color in the HSB color space. This time, we use a slider to let the user vary the hue. Slider is a widget that is similar to a scroll bar - it allows the user to select one value from a range of values by dragging - or sliding - a marker across a bar of values. The bar can have ticks - possibly with labels. (The range consists of discrete values, but we could make it appear continuous by offering as many - or more - values as the screen resolution offers.) Slider-like widgets are often used in audio and video players where they depict the progress and allow the user to replay or advance the media. Since our slider is used to select a hue, we construct a separate custom component that shows the spectrum of hues.

We are using a table to display the possible combinations of saturation and brightness for the selected hue. Naturally, I reuse the CustomComponent class from the preceding section.

Because Swing's JTable is intended for sophisticated applications such as spreadsheets, its API is quite intimidating. Because of this complexity, the design has numerous drawbacks that an application programmer has to deal with. The primary problem with the design is that the widget is column-centric - which is readily apparent from the TableModel interface. For instance, only columns can have headers. Another problem our application has to deal with is the handling of events: to determine which table cell has been clicked we need to listen to column-selection event and a row-selection event. As a rule of thumb, we should ban all the code that deals with the quirks of a framework within the lower layers of our software. Therefore, I constructed a SimpleTable class that deals with all the "dirty" code and offers a clean interface to my application. In particular, this class sends a single event when a table cell gets selected. Note that since my SimpleTable is a subclass of JTable, all the complex features can be used as well.

These are the applet's sources:


Animations and Java2D

Unlike other media frameworks, Java's APIs don't have a specialized facility that is dedicated solely to animations. Of course, we could simply construct a loop that does show a frame and then waits, e.g.:

while (moreFrames ()) {
  nextFrame ();
  long nextTime = System.currentTimeMillis () + delay;
  while (System.currentTimeMillis () < nextTime) {} // busy wait
}

This is, however, very inefficient, because the inner while loop hogs the CPU. Even if your program has nothing else to do, this is the wrong solution, because it can make the program feel unresponsive. (Everything happens within about 70 ms feels "immediate" if an action lets the user wait longer than that it's likely to feel "unresponsive".) In particular, there will be no way to stop the media because no user interface widgets are functional until the all the frames are played.

To the rescue come "threads". A thread is a (quasi)parallel execution sequence. (It's truly parallel only on a computer that has more than one CPU, but the OS tries to give each thread a "fair" slice of time to execute.) The subject of threads and parallel programming is complex and could be easily a subject of a separate lecture. It is also quite difficult to master in practice even for very seasoned experts. Deadlocks (the program freezes because threads wait for each to give up control), race conditions and starvation (a thread doesn't get time to execute) are only few of the common pitfalls. The history of Java APIs is a good example of how difficult the subject is: The original class Thread defined the methods suspend() and resume() that were supposed to do the two obviously very useful jobs - pausing a thread and continuing its execution. These methods as well as the even more obvious stop() method are now "deprecated", i.e. should not be used anymore, because, as it was discovered literarily several major JDK releases later, they are "inherently deadlock-prone". Since threads are such a core language feature, it is safe to believe that even the inventors of Java were not originally aware of the pitfalls! (Fortunately, there are only few problems if threads do not access the same data, but unfortunately, that is seldom the case in practice.)

The basic theory is simple: We define a class that extends java.lang.Thread, then construct a new object of this class and call its start() method. This will automatically call the run() method of your class and this method will run parallel to the code that called start().

class Player extends Thread {
  public void run () {
    while (true) {// or till the end
      // do something in parallel
    }
  }
}
...
new Player ().start ();
// do something else in parallel

Notice that we used a while loop within our run() method because that is typical for a thread, but this does not need to be implemented this way and we will see soon a case where a thread has no loops at all.

But let us first show another way of implementing a thread. Instead to extending java.lang.Thread we can also implement java.lang.Runnable. Then the equivalent snippet of code reads:

class Player implements Runnable {
  public void run () {// or till the end
    while (true) {
      // do something in parallel
    }
  }
}
...
Player player = new Player ();
new Thread (player).start ();
// do something else in parallel

Now the things become more complicated - different threads should not make changes to user interface components simultaneously, because that could cause all sorts of problems from visual inconsistencies to program freezes. And AWT and Swing have the opposite approach to dealing with the problem. AWT is conservative and makes sure that only one thread can change critical data at any given time - this is called being "thread-safe". This is achieved by "synchronizing" all the code that deals with the user interface components with respect to a common object - the "lock". The lock guards a block of code. It holds a queue of threads that would like to grab it and execute the code. But only one of the threads is allowed to execute the code block. All the other threads have to wait until the currently executing thread releases the lock - i.e. leaves the synchronized block of code - then the next waiting thread will be able to continue. (This is the potential source of the dreaded deadlock problems when the executing thread wants to execute a block of code which is locked by another thread that is waiting somewhere else.) As you can imagine, all the management of queue, grabbing and releasing the lock costs time - that's why calling a synchronized method takes about a magnitude longer than calling a regular method.

To save time and make Swing feel less "sluggish", changes to Swing GUI are NOT thread-safe. So if code that is not thread-safe is so dangerous, why did you not run into problems yet? If you do not use your own threads, you can pretty much ignore the issue, because everything that you do before you show() your main java.awt.Frame or javax.swing.JFrame is thread-safe. Also, all the code is thread-safe that is called in response to some event (actionPerformed() of a ActionListener, mousePressed() of a MouseListener, etc. - in short in any method that was added with addXXXListener() to a GUI component - of course only if you do not call it from another thread directly.) Such code is executed on the so-called "event-dispatch-thread" which is the thread where most of your program is running anyway. Also, if you do not call paint() directly, but only indirectly via repaint(), you can be sure that the code within your paint() method is executed in thread-safe manner. And if you cannot do any of the above, you can write:

class SwingUnsafeThread extends Thread {
  public void run () {
    // don't use Swing here at all! 
    SwingUtilities.invokeLater (new Runnable () {
      // this is now safe
    };
  }
}

So animation using threads is not that simple after all. You can use one of the "Timer"s for your animations. The java.util.Timer can be used with AWT and Swing, but if you use it with Swing you have to make sure that your code is thread-safe. Moreover, it does not "coalesce", i.e. if your code needs too much time in between consecutive invocations, the calls get "bunched up" and you will eventually run out of stack space. (This is not a problem if you use repaint() because the "repaint manager" will do the coalescing behind the scenes for you.) Swing has its own Timer that ensures thread-safety and can do the coalescing.

I prepared several programs that use a thread to perform animation. The simplest is a "digital clock" that is nothing else than a glorified label that displays the formatted hours, minutes and seconds. The more interesting part is the Timer thread that updates the hours, minutes and seconds fields based on the system's clock and then waits a second. This is the pseudo-code of its run() method:

    public void run () {
while (true) {// endless loop
// get system time and split it into hours, minutes and seconds
// let the clock display it
// wait 1 second; ignore interruptions
try {sleep (1000);} catch (InterruptedException dummy) {}
}
}

Notice that

  1. we have indeed implemented an endless loop, and
  2. we choose to ignore an exception!

Here, it is both the correct solution, because:

  1. the thread will terminate anyway when the program ends, and
  2. if the thread should be interrupted, then we just show the same time again...

This is the applet digital_clock and this is its source sources:

Caveat: Our applet is not "well behaved" because if we run it in a web page and the user leaves this page, our run() method will continue executing, even though the clock cannot be seen. A well behaved applet would create a new Timer and start it within its own start() method and let it "run out" within its stop() method. (By running out gracefully we mean to introduce a boolean variable that controls the while-loop and set it to false.)

The next two applets use a similar thread mechanism, but demonstrate the use of Java2D, a sophisticated drawing package that is now integral part of core APIs. Java2D allows you to define not only primitive shapes such as rectangles, ovals, arcs and polygons, but arbitrary shapes defined by a path that can be composed from lines, quadratic and cubic curves (b-splines). These shapes can be filled with colors, textures - aka (tiled) images - or a color gradient and can have an outline that can be not just solid, but composed of "dashes" defined in a very flexible manner. Moreover, Java2D can give you access to the shape of a character glyph (or sequence of glyphs for a String) as it is defined by any of the available fonts. But that's not all - Java2D lets you transform such shapes using "affine" transformations. Simply said, "affine" transformations are all those that preserve parallelity. Translation (moving by any distance in any direction), rotation, scaling, and shearing (akin to skewing - think about pulling a corner of a rectangle to the side to get a parallelogram) are the four basic types of affine transformations. But wait, it get's better - any combination of affine transformations is again affine - so the class of affine transformations is quite rich. (But there is no affine transformation that will make a trapezoid from a rectangle, that would necessitate to put originally parallel sides onto two lines that intersect and that can't be affine by definition!) For legacy reasons - yes Java is not immune, either - the Java2D capabilities are "hidden", because you painting method is seemingly getting only a java.awt.Graphics object as a parameter. But this object is a java.awt.Graphics2D object in disguise - you can simply cast it into Graphics2D and use its full potential. Notice that you can either perform the affine transformations on the shapes that you need to draw or you can choose to transform the java.awt.Graphics2D object itself. But watch out - to get the same effect the sequence of transformations must be applied in reverse!

The applet text_animation, simply keeps rotating and stretching a text string and changing its color hue. To avoid flickering, the offscreen buffering - also called double-buffering - technique is used: The paint() method first draws everything into an off-screen image "buffer" (using the associated Graphic object) and this buffer is than drawn in a single step into the target Graphic object. Drawing into off-screen buffer is faster and does not have any visual effects. To speed up things, we also (re)create the buffer only if the component size changes. This can be achieved by overriding the method setBounds(). (Note that Swing provides automatically for offscreen buffering so this technique is mainly needed when you use AWT.) This is the source of the applet and its archive:

The applet analog_clock uses the same threading technique as the other applets in this section, but takes advantage of a few more complex Java2D features. To produce the dial of an analog clock, it extracts the numeric glyphs from a font and moves, scales and rotates them into the correct position on the dial. Again, this applet uses an off-screen image buffer. Moreover, it needs to use another sometimes needed and not often discussed technique - how to override the addNotify() method. The problem is that we need to extract the glyphs for the dial's numbers - and we would like to do it only once, at the beginning. But the glyphs are only available via an appropriate FontRenderContext object and such object must be obtained via a Graphics object. The problem is that we cannot get a Graphics object, or access to any resources of the component such as its font or offscreen images before they become available - this does not happen until the component is "added" to a GUI container that is visible on the screen. (Ok, when paint() is called, we have the needed Graphics object and we could have there an if-statement that checks whether the glyphs are initialized and performs the initialization if it has not been done yet. But you will probably agree that this not very elegant...) So how do we know when the component's resources become available? It happens precisely as the result of calling the obscurely named addNotify() method. So we can override this method and do our initialization in the overridden code. But you have to be very careful, not only must your addNotify() method's signature be exactly the same, but the first statement of the overridden method must be super.addNotify(). This lets the superclass do its job of providing the component with the resources it needs. Only then you can perform your own initialization chores.

This is the source of this applet and its archive:

Finally, in the applet movie we show how to read a sequence of images based on the values of applet 's parameters and how to show them as a sequence of frames - it's really more a "slide show" than a movie. An often useful technique should be mentioned here - how to get a URL of a resource in some manner that can be used both in an applet and in a standalone application. (Applets can use the "codebase", but there is no codebase within an application. In an application there is the "current directory", but security restrictions prevent you to use this concept in an applet.) The following technique is recommended and often employed whenever Swing's ImageIcon class is used: The only precise location of files that the Java run-time system knows is that of the class files, whether they are provided as individual files or reside within an archive file (i.e. zip- or jar-file) - after all the system must load your classes from somewhere! So to create the correct URL of a resource file, you can provide its path relative to the location of a known class file. Suppose that your class is called ics.foo.Bar and you would like to access a image.gif file in the same directory where the file ics.foo.Bar.class is located. Then you can create the URL of the gif file as follows:

URL url = ics.foo.Bar.class.getResource ("image.gif");

Note that url will be set to null if such a file doesn't exist. (Now you should wonder why an exception is not thrown - I have certainly no explanation for this inconsistency...) The above snippet of code is advanced Java - you should know that each class in Java has automatically an associated <qualified-class-name>.class object that represents this class. Somewhat simpler and more robust version of the above code is:

URL url = getClass ().getResource ("image.gif");

This is more restrictive because now the gif file must be in the same location as the class file of the class where this code resides. On the other hand, you do not need to change it if you decide to rename the class or put it into another package. (Note also that you can use "../image.gif" or even "../../image.gif" and then put your resource file into the parent or grandparent directory. However, "../../../image.gif" does not work anymore, as you can go only as many steps up as the number of parts in the package name of your class and our package has only two parts - ics and foo.)

This is the source of the movie applet and its archive:

Our movie has of course a big drawback - it doesn't feature any sound. Therefore, I have also prepared a nother version that plays sound files along with the slide show - a movie_sound applet. To make things simple, this applet simply plays a new sound file with every frame. Naturally the sounds I recorded have varying length. As you can hear, this conflicts with the timing of our frames which are changed after a fixed, constant delay. So there are either anoying pauses or - even worse - some sound clips are cut off by the following clip. There is unfortunately no easy way to remedy it within the simple audio framework available to an applet. (You could measure the durations of each clip and provide them within an applet parameter, but this is a very, very clumsy solution...)

This is the source of the movie_sound applet and its archive:


Low-level Media Access: Playing Controlled Sound with JavaSound

In the last applet, we had to face the limitations inherent to the simplicistic standard that the original JDK framework provided for applets: An applet can access an audio clip, play it, stop playing it, and loop it. The concept of "looping" is interesting: it means that when the clip finishes playing, it's restarted automatically, i.e. plays from the beginning. There is, however, no way to find only when the sound has finished playing. This is a grevious violation of one of the basic tennents of good design of a framework:

Principle: A well designed framework provides access to ALL the atomic functionality as well as to the composite functionality that is most likely to be used.

Finding out when a sound clip finishes playing is definitively an example of atomic functionality that is not provided. I would also argue that looping is not very likely to be used because a repeated sound clip simulates a "broken record" that becomes quickly anoying. A well designed framework should not encourage bad conceptual design!

Note: There is probably no better (actually worse) example of how providing a questionable feature encourages bad conceptual design than web pages that offer fill-in forms. Because html supports the two buttons "Submit" and "Clear", most web designers feel that they have to use both of them. While there is no problem with submitting the contents of the form, clearing the form is in 99% of the cases a very bad feature, because it destroys all the effort the user put into filling out the form. If the user happens to click "Clear" by mistake, all the precious time she put into filling the form's fields is lost. (Of course, if there was an "undo" option then clearing the form will become a possible, even if seldom used option.) The "Clear" button was probably adopted from the familiar "OK"-"Cancel" options offered in dialog boxes that change the parameters. There, the design makes sense, because it's offered in a modal dialog and the parameters have some current values - "Cancel" then means "keep the current values". Web forms are mostly used to enter new information and not to alter values of existing parameters so the analogy is misplaced. Moreover, a form on a web page is rarely displayed in a separate window and even if it is, it can't be modal so the user can always close the window or browse to another page (e.g. go back to the previous one) if she decides not to submit the form. Since the user will either browse further or close the browser as her next action, clicking "Clear" is just one more extra action that is completely superfluous. So providing a "Clear" button is almost always a bad design choice!

Note that my previous applets did emulate the "broken record". I could argue that such a design is justifiable because it's long enough to be percieved as the "ticker" concept familiar from news TV channels that show continuously the stock prices. But I admit freely that the argument is facetious. A product-ready software would typically provide control buttons that allow the viewer to play, pause, position (e.g. restart) the clip, etc. The code necessary to provide this functionality would, however, unnecessarily complicate the sources.

The newer versions of the JDK framework now incorporate a set of APIs that support the atomic functionality that we need. The APIs are summarily called JavaSound and support not only sampled audio but also playing midi files. The difference between midi and sampled sound is analog to the distinction between vector and bitmapped graphic images. Bitmapped images store the color values for individual pixels - that's why they can be easily displayed on the screen which is a also composed of individual pixels. In contrast, vector graphics defines an image as an assembly of mathematically defined shapes. To display such an image on the screen, these shapes must be rendered aka converted into a bitmapped image. Vector graphics tend to be much smaller than their rendered equivalent bitmaps, but rendering necessitates extra processing time. On the other hand, while vector images can be resized exactly, resizing bitmaps entails either inserting extra pixels or reducing the available information to fewer pixels that typically introduces visual artifacts. Also, some type of images isn't suitable for vector graphics, e.g. photographic images.

Midi is analog to vector graphics. It's only suitable for the abstract definition of music and cannot, for instance, define speech. Midi files are comparably small. Midi sound can be rendered - i.e. converted to sound wave samples - either in software or directly in hardware. In contrast, sampled sound is analog to a bitmapped image. Consider a bitmap of a photographic image - the neighbouring pixels contain color information that is a "sample" of the real world colors at the time the camera took the picture. These samples vary along the two spacial dimensions. Sampled audio is like one pixel line in a bitmapped image. Only the value of each sample is not color information, but the current amplitude of the sound and the samples vary in time and not space. As bitmaps can have lower and higher resolution, i.e. more or less pixels per inch, so sounds can be sampled more or less frequently, i.e. with higher or lower frequency. Of course, the higher the frequency, the more accurate is the sound. While CD records are sampled at 44.1 kHz - i.e. 44,100 samples per second, 22 kHz is roughly equivalent to FM radio, 11 kHz to AM radio and 7 kHz to a phone line. Also the number of bits per sample influence the quality of the images and sounds. With 24-bits (8 bits in each red, blue and green dimension) we can distinguish among 16.7 million shades of color. Sound is typically sampled with either 8 or 16 bits per sample. Also, sound can have either one or two channels, i.e. either mono or stereo. Sampled sound can be very storage intensive: 1 hour od CD quality stereo sound needs 635 MB (60 min * 60 s/min * 44,100 samples/s * 16bits/sample * 2 channels / 8bits per byte). But even 10 minutes of phone quality sound (7 kHz, 8 bit, mono) needs over 4MB. In other words one floppy disk can hold roughly 20 seconds of low-quality sound... Of course, sound data can be compressed, but loss-less compression can reduce the storage requirements only by factor 1/2 and lossy compression methods introduce artifacts that musician's ears can hear. Nevertheless, newer compression methods (Mpeg layer III or mp3 and Ogg Vorbis) can produce comparably small sound files in acceptable quality.

A variety of formats have been defined for storing sound samples compressed and uncompressed. The variety account, for instance, for different interpretation of bits (signed and unsigned) or which of the two bytes in a 16 bit sound is the high and which is the low one (big- and little-endian).

PCM (Pulse Code Modulation) is the simple method for storing uncompressed audio samples. Windows "Sound Recorder", for instance, produces by default PCM unsigned format at 22 kHz mono. On Unix-based computers the a-law and mu-law formats are common. The AIFF format is common on the Macintosh platforms. A software (or hardware) units that can read a stream of bytes encoded in a particular format and convert it to audio samples as well as take audio samples, convert them to a specific format and write the raw data to a stream is called a codec (for coder and decoder).

JavaSound hides some of these complexities from us. It makes it easy to convert a stream of data into an audio stream. In the process, the header information in the beginning of the stream's is examined to determine the encoding format and a codec that can interpret this format is identified. It is also comparatively easy to prepare a "line" that can play the sound. Similarly we can easily open an audio stream where we can write audio samples.

But if you try to look for the methods play(), pause() or stop() you will not find it in JavaSound. To play a sound, we have to open a stream, convert it to an audio stream, open a line that can play it and then read raw bytes from the stream into our own buffer and write the contents of the buffer to the line. In this sense, JavaSound is a decidely low-level layer API. (One can argue that this design violates the second part of our design principle - since the composite functionality of playing a sound is definitively very likely to be needed, the framework should provide it. To be fair, the Java Media Framework - JMF - offers this functionality, but it's not part of the base JDK APIs.)

Naturally, we can write our own API that offers the composite functionality that JavaSound lacks. Our class Sound is a good first attempt. It encapsulates all the complexities involved in opening a sound clip and playing it. It also sends an event to registered listeners when the soud clip reaches the end. This class is far from perfect (it leaves the correct handling of threads to the programmer) or complete (for instance, it still lacks the pause() and stop() methods.)

The movie_JavaSound_events applet uses the Sound class to make our slide show more smooth. The next slide and the next sound are not displayed until the applet receives the event that the current sound clip finished playing.

Notice that the applet must do some fancy footwork to deal with activating and deactivating the player thread. I programmed it in a very generic fashion so that you can use it whenever you need to pause a thread (or in other words, let it wait until it's woken up) and wake it up from another thread. This is itself a complex topic that is best explained in the context of a lecture on operating systems or concurrent programming.)

This is the source of the movie_JavaSound_events applet and its archive:


Custom Event Handling

The movie_JavaSound_events applet presented in the previous section incorporates another very useful feature - it demonstrates the software framework necessary to send custom events to listeners. Such custom event handling frameworks are not only useful in constructing new GUI widgets, but turn out to be a core facility of JavaBeans - the software components created with Java. As such software components are envisioned as the core building blocks of the future software systems, the importance of custom even handling can be hardly overemphasized. (This is also evidenced by the fact that C# - Microsoft's programming language developed as a response to Java - provides direct language constructs that support building of components, such as properties and events.)

A custom event handling frameworks must provide the following four facilities:

  1. A class that defines the type of your custom events,
  2. an interface that establishes the contract that the recepients - or listeners - of your events must fulfill if they want to receive your events,
  3. a data structure where the listeners are stored and access methods that add and remove a listener, and
  4. method(s) that send an event to all registered listeners.

The listener interface (2.) will contain one or more methods that further identify the event. For each of these methods you will need one corresponding method in 4. that send the event.

If your listener interface comprizes more than one method you should also provide an "adapter" class that implements the listener interface with "dummy" methods that have empty bodies.

It is a good idea to name these all the pieces that your framework exposes to the outside environment according to established naming conventions:

  1. XxxEvent class
  2. XxxListener interface
  3. addXxxListener() and removeXxxListener() methods

I also recommend that you name the internal pieces that your framework in a consistent way:

  1. listeners data structure
  2. dispatchMethod1(), dispatchMethod2(), etc. if the XxxListener interface contains the methods method1(), method2(), etc.

While the first two steps 1. and 2. - the event class and listener interface - are accomplished with comparably little effort, the correct way to construct the remaining parts of the framework is surprisingly intricate provided that you want to guarantee that your software component functions well in a multi-threaded environment.

To be a good citizen, your XxxEvent class should extend the java.util.EventObject superclass or one of its subclasses. Similarly, your XxxListener interface should extend the java.util.EventListener superinterface or one of its subinterfaces. A sample implementation of such a framework is exemplified in our applet:

public class MediaEvent extends java.util.EventObject {
   
  private long time;
  
  public MediaEvent (Media media, long time) {
    super (media);
    this.time = time;
  }
  
  public Media getMedia () {return (Media) getSource ();}
  
  public long getTime () {return time;}
  
}


public interface MediaListener extends java.util.EventListener {


  public void mediaPaused (MediaEvent event);
  
  public void endOfMediaReached (MediaEvent event);
  
}

Notice that I extended the actual sources somewhat to demonstrate a more generic solution: the above event class supports the property time and the listener interface has two methods. Notice also that the event class also provides the method getMedia(). While none of the event handling frameworks (including AWT and Swing) I have seen supports getting the "source" (i.e. the object who sends the event) using its own type via a well-named method, I warmly recommend this solution, as it makes the programs that use your framework more readable and less error-prone. (It also bans the ugly type cast from the user programs.) I also recommend to name the listener's method using a verb in past tense: yyyOccured(), zzzReached(), etc. After all, you want to express that some event "happened".

Principle: Always think how your names will look in the program that uses them rather than what they mean in your implementation.

The management of listeners is also "uneventfull" (excuse the pun...):

public class Sound extends Media {

private ArrayList<MediaListener> listeners = new ArrayList<MediaListener> ();
synchronized public void addMediaListener (MediaListener listener) {
listeners.add (listener);
}

synchronized public void removeMediaListener (MediaListener listener) {
listeners.remove (listener);
}

}

Notice that we could use any other "collection" classes rather than ArrayList: Vector, Set, even Hashtable or Map. More importantly, notice that the addXxxListener() and removeXxxListener() need to be synchronized to function correctly in a multi-threaded environment. If we didn't synchronize the methods then while one thread is adding a listener and the collection is in an inconsistent state, another thread could be given the chance to add or remove a listener. This will very likely result in a disaster as the collection may become incosistent.

The need to synchronize the access to our collection of listeners makes the last piece of the puzzle quite hard to implement. The simple attempt to implement the dispatchMediaPaused() method may look as follows:

  public void dispatchMediaPaused (MediaEvent event) {
for (MediaListener listener : listeners) {
listener.mediaPaused (event);
}
}

Unfortunately, this attempt may fail because our iterator could encounter an inconsistent collection if another thread added or removed a listener during the iteration. Now you probably think that we can simply synchronize the entire dispatch method to resolve the problem. Again, this will not work. This time, the reasoning is more subtle. Suppost that in our call to listener.mediaPaused() the listener tried to add another listener. (Or, which is more likely, remove itself from our list of listeners.) But when is calls the removeMediaListener() method, the disaster is immediate - because both dispatchMediaPaused() and removeMediaListener() methods are synchronized with respect to the same object (the this object), removeMediaListener() has to wait until dispatchMediaPaused() finishes and releases the lock on this. But dispatchMediaPaused() can't proceed until removeMediaListener() finished because removeMediaListener() was called from within dispatchMediaPaused(). Each method waits for the other to finish... This is a prime example of the dreaded deadlock!

The solution is complex and can be quite inefficient. There are two constraints that we need to satisfy:

  1. We must make the calls to our listeners outside any synchronized block, and
  2. we need iterate over a data structure that no other thread can alter.

Therefore we first copy all the listeners into another data structure - we can synchronized the code block that creates the copy. Outside of this synchronized block, we can traverse the cloned data structure and call the listeners. This is the code that illustrates this solution - it uses a local array to hold the copied references to our listeners:

  public void dispatchMediaPaused (MediaEvent event) {
MediaListener listeners [] = null;
synchronized (this) {
int size = this.listeners.size ();
if (size == 0) {return;} // there are no listeners; abort
listeners = new MediaListener [size];
this.listeners.toArray (listeners);
}
for (MediaListener listener : listeners) {
listener.mediaPaused (event);
}
}

Notice that since I use the same name listeners for the local copy as well as for the instance variable, I must prefix the instance variable with this. You may prefer using a distinct name - I perceive the construct this.listeners as distinct, and justified because both structures hold the same contents and have the same purpose.

Notice also how using an array simplifies the code - for instance, we don't need the ugly cast because the array can be declared as holding elements of the actual MediaListener type.

The last step is to provide a common solution for both dispatchMediaPaused() and dispatchEndOfMediaReached() methods. We notice that making a copy of the listeners is identical to both methods and can thus be extracted into another method. Moreover this new method can be synchronized directly:

  public void dispatchMediaPaused (MediaEvent event) {
MediaListener listeners [] = listeners ();
if (listeners == null) {return;}
for (MediaListener listener : listeners) {
listener.mediaPaused (event);
}
}
  public void dispatchEndOfMediaReached (MediaEvent event) {
MediaListener listeners [] = listeners ();
if (listeners == null) {return;}
for (MediaListener listener : listeners) {
listener.endOfMediaReached (event);
}
}
  synchronized private MediaListener [] listeners () {
int size = this.listeners.size ();
if (size == 0) {return null;}
MediaListener listeners = new MediaListener [size];
this.listeners.toArray (listeners); return listeners;
}

The above code can be still simplified if define an empty array as a constant and return it from listeners() if there are no listeners. Then we can omit the if-statements that check for null within our dispatch methods.


Generic Event Handling: OO Design "To Da Max"

Isn't it tedious to program a custom event handling every time from scratch? The standard Java API have indeed dozens of event dispatching features, Swing alone has introduced a slew of new ones. And JavaBeans, the standard blueprint for implementing software components in Java requires that a component provide notification of changes via event dispatching. It seems that there should be an object-oriented design that allows to define a custom event handling without sacrificing the clarity of nice method names and without repeating the tedious, complicated and error-prone code that makes event dispatching thread-safe.

Indeed there is such a software pattern, albeit it requires an advanced understanding of OO design.

The applet movie_generic_events incorporates such a generic event handling.

First we note the obvious difficulty - our solution must support any types of listener interfaces and these interfaces have various names. Remember the problem of plotting various mathematical functions in the beginning of the lecture? There was a similar difficulty - the plotting was a common functionality but methods with different names - Math.sin(), Math.cos() and Math.tan() - had to be called to get the functions' values. Our solution was to define an abstract superclass that implemented the plotting using an abstract method. The different subclasses then implemented this abstract method using the different method names.

Our solution will use exactly the same software pattern. We define an abstract superclass Dispatcher that takes care of the chore of dispatching an event to listeners in thread-safe manner in the dispatch() method. This method will call an abstract method dispatchTo() for each of the listeners. The client software that uses our framework will then define for each method in its listener interface a concrete subclass that implements dispatchTo() using a call to this method.

This is the Dispatcher class:

  abstract public class Dispatcher<Listener extends EventListener
      , Event extends EventObject> {

    private ArrayList<Listener> listeners = new ArrayList<Listener> ();

    public synchronized void addListener (Listener listener) {
      listeners.add (listener);
    }

    public synchronized void removeListener (Listener listener) {
      listeners.remove (listener);}
    }

    public void dispatch (Event event) {
      ArrayList<Listener> listeners = null;
      synchronized (this) {
        if (this.listeners == null) {return;}
        listeners = (ArrayList<Listener>) this.listeners.clone ();
      }
      for (Listener listener : listeners) {// dispatch event to all listeners
        dispatchTo (listener, event);
      }
    }

    public abstract void dispatchTo (Listener listener, Event event);
  }

Did you notice how the parametrized classes in Java 5 make our code well specified and self documenting? (Just read the first line as "class Dispatcher to a Listener that extends EventListener of an Event that extends EventObject" - that's exactly what we are trying to accomplish.) And at the same time, the compiler can check whether the subclasses are well behaved and provide dispatchers for the right types.

Now our client class Media can simply define a subclasses of our Dispatcher for sending end of media events:

  private Dispatcher<MediaListener, MediaEvent> endOfMediaDispatcher 
      = new Dispatcher<MediaListener, MediaEvent> () {
    public void dispatchTo (MediaListener listener, MediaEvent event) {
      listener.endOfMediaReached (event);
    }
  };

  private Dispatcher<MediaListener, MediaEvent> mediaPausedDispatcher 
      = new Dispatcher<MediaListener, MediaEvent> () {
    public void dispatchTo (MediaListener listener, MediaEvent event) {
      listener.mediaPaused (event);
    }
  };

We are almost at the end - our clients are simple to implement and all the difficult code that insures thread-safety is taken care of by a well debugged standard superclass. Also, thanks to Java 5, there are no ugly casts in our clients' implementation of dispatchTo() - the compiler knows that the parameters have the correct MediaListener and MediaEvent types.

But we have not discussed the last aspect of our framework - the registration of listeners. As it is implemented above, each of our client dispatchers has his own list of clients, so that we have as many lists as there are methods in the listener interface listeners must be added or removed from each of them. This unnecessary and wastes memory.

The solution is simple - the client has to create a list for listeners and provide our Dispatcher with the reference to this list. Since the best place to pass this reference is in the constructor - to make sure that the client didn't forget to set it later on -, the client concrete dispatchers also need to receive it as a parameter in their constructors. Assuming that the list has the type ListenerList<MediaListener>, then for instance our endOfMediaDispatcher will have the following form:

  private Dispatcher<MediaListener, MediaEvent> endOfMediaDispatcher 
      = new Dispatcher<MediaListener, MediaEvent>
       (ListenerList<MediaListener> listeners) {
    ...
  };

We now our Dispatcher can be simplified, because the client will register listeners directly using the list and we can drop these methods from the Dispatcher:

  abstract public class Dispatcher<Listener extends EventListener
      , Event extends EventObject> {

    private ListenerList<Listener> listeners;

    public Dispatcher (ListenerList<Listener> listeners) {
      this.listeners = listeners;
    }

    public void dispatch (Event event) {
      for (Listener listener : listeners) {
        dispatchTo (listener, event);
      }
    }

    public abstract void dispatchTo (Listener listener, Event event);
  }

But wait a moment - aren't we back to the simple solution that isn't thread-safe? Where is the synchronized block that clones the list of listeners to ensure thread-safety?

The trick is hidden in the for-each loop. The loop just a nice shortcut for:

      Iterator<Listener> iterator = listeners.iterator ();
      for (; iterator.hasNext ();) {
        Listener listener = iterator.next ();
        dispatchTo (listener, event);
      }

Therefore we just need to ensure that the iterator() method in our listeners' list returns an iterator to a clone and not to the list itself! This is the trick:

  public class ListenersList<Listener extends EventListener> {

    private ArrayList<Listener> listeners = new ArrayList<Listener> ();
 
    public synchronized void addListener (Listener listener) {
      listeners.add (listener);
    }

    public synchronized void removeListener (Listener listener) {
      listeners.remove (listener);
    }

    synchronized public Iterator<Listener> iterator () {
      return ((List<Listener>) this.listeners.clone ()).iterator ();
    }
  }

As a last - rather decorative - improvement, we can provide an interface for such lists of listeners which makes our threat-safe list one of the possible classes that implement it. If we name this interface ListenersList then we don't even have to change anything in our Dispatcher code. Moreover, our client's dispatchers remain untouched:

Listeners' list returns an iterator to a clone and not to the list itself! This is the trick:

  public interface ListenersList<Listener extends EventListener> {

    void addListener (Listener listener);

    void removeListener (Listener listener);

    Iterator<Listener> iterator ();

  }

Of course, we need to find another name for our thread-safe list - the appropriate name will be SafeListenersList:

  public class SafeListenersList<Listener extends EventListener> 
      implements ListenersList<Listener extends EventListener> {
    ...
  }

Introducing an interface is not just an OO nicety - it allows a client to substitute their own implementation of the ListenersList. In a closed environment where we are sure that the listeners don't add or remove listeners - after all, that happens seldom - we could for instance opt for an unsafe list:

  public class UnsafeListenersList<Listener extends EventListener> {

    private ArrayList<Listener> listeners = new ArrayList<Listener> ();
 
    public void addListener (Listener listener) {
      listeners.add (listener);
    }

    public void removeListener (Listener listener) {
      listeners.remove (listener);
    }

    public Iterator<Listener> iterator () {
      return listeners.iterator ();
    }
  }

Such an unsafe list is much more efficient because it drops all synchronization - that's quite time-consuming - and doesn't need to construct a clone as it can iterate through the list itself.

The last remaining piece of the puzzle is the client's registration of listeners, and that's rather trivial. For example, our Media class can do it this way:

  public class Media  {


    private ListenersList<MediaListener> listeners 
        = new SafeListenersList<MediaListener> ();
	  
    protected Dispatcher<MediaListener, MediaEvent> endOfMediaDispatcher 
        = new Dispatcher<MediaListener>, MediaEvent> (listeners) {
      public void dispatchTo (MediaListener listener, MediaEvent event) {
        listener.endOfMediaReached (event);
      }
    };

    protected Dispatcher<MediaListener, MediaEvent> mediaPausedDispatcher ... 

    public void addMediaListener (MediaListener listener) {
      listeners.add (listener);
    }
  
    public void removeMediaListener (MediaListener listener) {
      listeners.remove (listener);
    }
  
  }

Notice that the addMediaListener() and removeMediaListener() registration method are not synchronized. If we used an UnsafeListenersList then synchronization isn't necessary and in our case the SafeListenersList synchronizes the registration methods already. In either case an additional synchronization would just introduce inefficiencies.

Now we are at the end - we have achieved our goal:

  1. We have a generic framework for all event handling, one of the most often used concepts in API libraries and software components
  2. A client doesn't need to be concerned about the intricacies of thread-safe event dispatching.
  3. The client can provide nice, self-documenting method names in their XxxListener interfaces.
  4. The client's implementation of event dispatchers follows a very simple pattern.
  5. The client can choose between a thread-safe or efficient, but unsafe event dispatching.

This entire exercise is a nice example of object-oriented design - our solution is all based on inheritance, abstract classes, interfaces, and polymorphism. Also, it's a nice example of how parametrized classes make Java code elegant.

So why is such even dispatching framework not embedded and supported directly within the standard JDK? (I assume that the Sun engineers are well versed in OO design so that this concept didn't escape their design decisions.) I presume that this is exactly because event dispatching is such an omnipresent software pattern. Such an important pattern must be efficient and our framework introduces inefficiencies: inner classes for each of the event dispatching methods (extra space) and nested calls (extra time) of overridden (again extra time) methods. This is a typical trade-off: elegance of software design, flexibility of reuse and programming safety versus efficiency.

These are the sources and the archive:


Sampled Sound - Decoding Format and Wave Display

Let's now return to our discussion of sound and show how to deal with individual samples. As we have discussed, there are many audio formats, so providing a program that can decode all these various formats would be a daunting task. Fortunately, there are many "codex" programs that can do it for us and JavaSound makes it quite easy to "transcode" a sound file - i.e. convert one format into another. The transcoding happens behind the scenes, we need simply to request an audio stream in a format that we can handle. The following snippet of code demonstrates how:

      AudioFormat format = stream.getFormat ();
if (format.getEncoding () != AudioFormat.Encoding.PCM_SIGNED) {
format = new AudioFormat (AudioFormat.Encoding.PCM_SIGNED,
format.getSampleRate (), format.getSampleSizeInBits () * 2,
format.getChannels (), format.getFrameSize () * 2,
format.getFrameRate (), true); // big endian
stream = AudioSystem.getAudioInputStream (format, stream); }

This code simply tells JavaSound's AudioSystem that we need a stream in PCM_SIGNED format (big-endian - that's the true in the last parameter) and converts our original stream to it.

I left the most important piece out - getAudioInputStream can throw an IllegalArgumentException that signifies that there is no codec that can perform the conversion. (Even though there may be no codec that can transcode the sound clip, there still may be a line that can play it!)

Now suppose that we were able to obtain a transcoded stream. Then we can decode the samples in PCM-signed big-endian format. The following snippet converts the raw samples stored in a buffer of bytes into an array of samples where the first dimension is the channel and the second is the index of a sample:

      int index = 0;
      for (int i = 0; i < samplesCount; i++) {
for (int channel = 0; channel < channelsCount; channel++) {
// assume PCM signed 16-bit
int data = ((int) buffer [index + 1] & 0x000000FF)
| (((int) buffer [index]) << 8);
index += 2;
samples [channel][i] = data;
}
}

Notice that the PCM format simply stores the raw sample data in a sequence of bytes.

The decoding of PCM 8-bit is even simpler - there is only one byte per sample so no shifts are needed and the index will be only incremented by 1:

          int data = (int) buffer [index];
index++;

Finally, little-endian format will simply reverse the order of bytes, i.e.

          int data = ((int) buffer [index] & 0x000000FF) 
| (((int) buffer [index + 1]) << 8);
index += 2;

The sample data can be used for instance to display the sound wave. The applet sound_samples displays the sound waves of several sample audio files. Notice how portions of a sentence and sometimes individual words can be clearly the distinguished in the sound wave. The applet's code must make some fancy footwork to compress a number of samples into a vertical single line in the display but I leave the details to the study of the source SoundWaveDisplay.

The applet's and the archive are at:


Responsive Swing Applications

The first version of my applet simply called the Sound's play() method from within the event listener:

    playButton.addActionListener (new ActionListener () {
public void actionPerformed (ActionEvent event) {
try {sound.play ();
} catch (MediaException error) {error.printStackTrace ();}
}
});

This made the applet very unresponsive - all the user interface was frozen until the sound played completely. This was because the play() method executed from withing the "event dispatchling" thread. There is a simple solution - we can construct another thread and play the sound there:

  private void play () {
Runnable player = new Runnable () {
public void run () {
try {sound.play ();
} catch (MediaException error) {error.printStackTrace ();}
}
};
new Thread (player).start ();
}

This code creates another thread and executes it. Notice that such a "wrapping of code into a thread" is a standard pattern and can be applied whenever you need execute a task in parallel.

The above solution is, however only applicable it there is no code that modifies the Swing's user interface. Suppose for instance that the user interacts with your program i.e. modifies Swing's GUI while your program tries to modify the GUI as well. Because the you have started another thread and modify the GUI from within this thread, there are two different threads that try to change Swing's internal state and it's very likely that one thread interrupts the other thread while Swing is in an inconsitent state and tries to change the state as well. This may lead to perpetually inconsistent state or at least to temporary mulfunctioning user interface.

So how can we make our code "thread-safe"? We need somehow to make sure that our code waits until Swing finishes it's task and make sure that Swing waits for our code to complete.

One solution is to supply a "lock" and synchronize our and Swing's code with respect to this object. This is the solution adopted in AWT. The consequence is that all the AWT code ineeds to be synchronized. Synchronization costs time and most programs do not modify the GUI from a separate thread. That's why Swing's designers decided to adopt another solution. Swing postulates a few rules and if you obide by these rules, your programs will be thread-safe:

  1. Any code in initializers and constructors can modify Swing.
  2. Any code executed from within an even listener can modify Swing.
  3. Any code in paintComponent() can modify Swing provided that you only call repaint().
  4. Any code in a thread that is passed as a parameter to SwingUtilities.invokeLater() or SwingUtilities.invokeAndWait() can modify Swing.

Arguably, these rules are not simple, but only the more experienced programmers - (:like us:) - need to be concerned and the efficiency improvement is likely to outweigh the complexity. After all, it's better to saddle experienced programmers with more complex rules to follow than all the users with slow application programs.

Let us demonstrate this with two code snippets from the applet sound_progress that has responsive user interface and shows the progress of playing our sounds in two different manners - as a red "cursor" line that sweeps across the sound wave and within a "progress bar" - a standard Swing widget. Our applet has three main threads:

  1. one that starts playing the sound - this makes the GUI responsive,
  2. another one that keeps updating the cursor line, and
  3. a third one that keeps updating the progress bar.

This is the method that starts playing the sound:

  void startPlayer () {
progressBar.setMaximum ((int) sound.duration ());
Thread player = new Thread () {
public void run () {
try {sound.play ();
} catch (MediaException error) {error.printStackTrace ();}
}
};
player.start ();
}

The method that defines the thread that keeps updating the cursor line is more complex as we need to keep track of time and wait a few milliseconds before we update the cursor line again:

  void startCursorUpdater () {
final long duration = sound.duration ();
Thread cursorUpdater = new Thread () {
private long time = 0;
public void run () {
long startTime = System.currentTimeMillis ();
while (time < duration) {
waveDisplay.updateCursor (time);
try {
synchronized (this) {wait (30);}
} catch (InterruptedException error) {}
time = System.currentTimeMillis () - startTime;
}
}
};
cursorUpdater.start ();
}

Notice that we had to synchronize the call to wait(). in order to avoid an exception that the our "thread doesn't own the monitor".

Finally, let's tackle the complex code. Our third thread will be exactly the same as in the last example with the only exception that we need to replace waveDisplay.updateCursor(time) with code that updates the progress bar. If we, however, simply wrote progressBar.setValue(time), we would violate one of the Swing's rules because we tried to modify one of Swings own widget from another thread. Therefore, we need yet another - inner - thread that will encapsulate our statement and pass it to SwingUtilities.invokeLater():

          Thread progressSetter = new Thread () {
public void run () {progressBar.setValue ((int) time);}
};
SwingUtilities.invokeLater (progressSetter);

This is the complete code:

  private void startProgressIndicator () {
final long duration = sound.duration ();
Thread progressIndicator = new Thread () {
private long time = 0;
public void run () {
long startTime = System.currentTimeMillis ();
while (time < duration) {
Thread progressSetter = new Thread () {
public void run () {progressBar.setValue ((int) time);}
};
SwingUtilities.invokeLater (progressSetter);
try {
synchronized (this) {wait (30);}
} catch (InterruptedException error) {}
time = System.currentTimeMillis () - startTime;
}
}
};
progressIndicator.start ();
}

The applet's and the archive are at:


Responsive Swing Applications

The first version of my applet simply called the Sound's play() method from within the event listener:

    playButton.addActionListener (new ActionListener () {
public void actionPerformed (ActionEvent event) {
try {sound.play ();
} catch (MediaException error) {error.printStackTrace ();}
}
});

This made the applet very unresponsive - all the user interface was frozen until the sound played completely. This was because the play() method executed from withing the "event dispatchling" thread. There is a simple solution - we can construct another thread and play the sound there:

  private void play () {
Runnable player = new Runnable () {
public void run () {
try {sound.play ();
} catch (MediaException error) {error.printStackTrace ();}
}
};
new Thread (player).start ();
}

This code creates another thread and executes it. Notice that such a "wrapping of code into a thread" is a standard pattern and can be applied whenever you need execute a task in parallel.

The above solution is, however only applicable it there is no code that modifies the Swing's user interface. Suppose for instance that the user interacts with your program i.e. modifies Swing's GUI while your program tries to modify the GUI as well. Because the you have started another thread and modify the GUI from within this thread, there are two different threads that try to change Swing's internal state and it's very likely that one thread interrupts the other thread while Swing is in an inconsitent state and tries to change the state as well. This may lead to perpetually inconsistent state or at least to temporary mulfunctioning user interface.

So how can we make our code "thread-safe"? We need somehow to make sure that our code waits until Swing finishes it's task and make sure that Swing waits for our code to complete.

One solution is to supply a "lock" and synchronize our and Swing's code with respect to this object. This is the solution adopted in AWT. The consequence is that all the AWT code ineeds to be synchronized. Synchronization costs time and most programs do not modify the GUI from a separate thread. That's why Swing's designers decided to adopt another solution. Swing postulates a few rules and if you obide by these rules, your programs will be thread-safe:

  1. Any code in initializers and constructors can modify Swing.
  2. Any code executed from within an even listener can modify Swing.
  3. Any code in paintComponent() can modify Swing provided that you only call repaint().
  4. Any code in a thread that is passed as a parameter to SwingUtilities.invokeLater() or SwingUtilities.invokeAndWait() can modify Swing.

Arguably, these rules are not simple, but only the more experienced programmers - (:like us:) - need to be concerned and the efficiency improvement is likely to outweigh the complexity. After all, it's better to saddle experienced programmers with more complex rules to follow than all the users with slow application programs.

Let us demonstrate this with two code snippets from the applet sound_progress that has responsive user interface and shows the progress of playing our sounds in two different manners - as a red "cursor" line that sweeps across the sound wave and within a "progress bar" - a standard Swing widget. Our applet has three main threads:

  1. one that starts playing the sound - this makes the GUI responsive,
  2. another one that keeps updating the cursor line, and
  3. a third one that keeps updating the progress bar.

This is the method that starts playing the sound:

  void startPlayer () {
progressBar.setMaximum ((int) sound.duration ());
Thread player = new Thread () {
public void run () {
try {sound.play ();
} catch (MediaException error) {error.printStackTrace ();}
}
};
player.start ();
}

The method that defines the thread that keeps updating the cursor line is more complex as we need to keep track of time and wait a few milliseconds before we update the cursor line again:

  void startCursorUpdater () {
final long duration = sound.duration ();
Thread cursorUpdater = new Thread () {
private long time = 0;
public void run () {
long startTime = System.currentTimeMillis ();
while (time < duration) {
waveDisplay.updateCursor (time);
try {
synchronized (this) {wait (30);}
} catch (InterruptedException error) {}
time = System.currentTimeMillis () - startTime;
}
}
};
cursorUpdater.start ();
}

Notice that we had to synchronize the call to wait(). in order to avoid an exception that the our "thread doesn't own the monitor".

Finally, let's tackle the complex code. Our third thread will be exactly the same as in the last example with the only exception that we need to replace waveDisplay.updateCursor(time) with code that updates the progress bar. If we, however, simply wrote progressBar.setValue(time), we would violate one of the Swing's rules because we tried to modify one of Swings own widget from another thread. Therefore, we need yet another - inner - thread that will encapsulate our statement and pass it to SwingUtilities.invokeLater():

          Thread progressSetter = new Thread () {
public void run () {progressBar.setValue ((int) time);}
};
SwingUtilities.invokeLater (progressSetter);

This is the complete code:

  private void startProgressIndicator () {
final long duration = sound.duration ();
Thread progressIndicator = new Thread () {
private long time = 0;
public void run () {
long startTime = System.currentTimeMillis ();
while (time < duration) {
Thread progressSetter = new Thread () {
public void run () {progressBar.setValue ((int) time);}
};
SwingUtilities.invokeLater (progressSetter);
try {
synchronized (this) {wait (30);}
} catch (InterruptedException error) {}
time = System.currentTimeMillis () - startTime;
}
}
};
progressIndicator.start ();
}

The applet's and the archive are at:


Playing Video with JMF

There are numerous frameworks that play video media on a computer. Two of them allow us to use them within Java programs - Java Media Framework (JMF) and Quicktime. While Quicktime - developed by Apple - is a older and more mature (and more sophisticated) framework, JMF - developed mainly by Sun and IBM - is free and since the sources are available, an experienced programmer can study the code for instance to get around bugs.

Both frameworks allow us to play, capture, and transcode media. You can even transmit media streams across a network. In order to use JMF you have to download it from its home and install it on your computer. Since JMF is not a standard part of the JDK distribution, the users of your programs will have to downdoad and install JMF as well. (You can automate this process if you decide to use WebStart.)

Before you proceed, please read the sections 1-4 of the JMF Programmer's Guide. In particular, consult the state diagram depicting the states a player goes through:

The methods that you can call to change the state are shown in blue starting with a lowercase letter.

Playing a video stream with JMF is relatively simple - you need to

  1. create() a Player (typically using a URL of a video file),
  2. realize(), prefetch() or directly start() the player
  3. provide a ControllerAdapterer that implements the realizeComplete() method
  4. in realizeComplete() you have to fetch the visual components (video and controls) and integrate them within your GUI.

Note that you can call directly start() on a unrealized player and the player will go through all the chain of states till it reaches the "Started" state at the end of the chain. Of course your listener will receive all the events when the states change on the way.

The following snippet of code creates the player and "prefetches" its content.:

      player = Manager.createPlayer (video.url);
player.addControllerListener (new ControllerAdapter () {
public void realizeComplete (RealizeCompleteEvent event) {display ();}
}); player.prefetch ();
On the way to prefetching the video, the player enters the "realized" state - that's when enough information has been read to know whether there is a codec for the video's format and what is the width and height of the video screen. When the player reaches this state, JMF can provide us with the component that displays the video and with a control bar that allows the user to start and pause the video, position it, mute the sound, etc. Therefore, we choose listen to the realizeComplete() event and now we can attach the player's components to our GUI:
  protected void display () {
screen.add (player.getVisualComponent (), BorderLayout.CENTER);
screen.add (player.getControlPanelComponent (), BorderLayout.SOUTH);
}

The above code presupposes that there is a panel screen with BorderLayout.

The applet video allows you to view several videos. (Please make sure that JMF is installed locally on your computer ans functions correctly before playing the applet.)

This is the source:


Media in 3-D

Another Java package - Java3D - allows us to create and display scenes 3-dimensional objects. Moreover, Java3D allows us to define sophisticated animations. Java3D is another "non-standard" package that has to be downloaded and installed on a client machine before the programs that use it can be executed.

Java3D is a very complex framework - it's specifications have over 600 pages! I recommend that you read the simpler tutorial. Java3D home lists a plethora of sample projects and useful links to get you started.

This is just a very brief enumeration of the most important concepts and features of Java3D:

There are numerous pitfalls that you can fall into - typically you forget to define a crucial property and either your program will crash with an exception or - which is worse - you objects do not show in your screen. I recommed that you start with a simple scene from one of the quite extensive collection of demo programs and slowly add the functionality that you desire. These are some of the pitfalls that you may encounter:

The applet earth demonstrates several simple as well as more advanced features of Java3D: (Please make sure that you have downloaded and installed Java3D on your computer before you access the applet's web page.

The applet greetings shows you how to extrude textual strings into 3D shapes and use them within your sceen graph.

Please study the sources of the applets for details:

Note: The SceneTree class is yet another a very good demonstration of how to implement a tree model required by JTree based on another set of tree traversal methods. Less that five statements are needed to define the tree model that displays the scene graph with JTree! (The only hitch is that the capability of reading the childern of all the Group nodes must be set so that our tree model can access them. I solved the problem by defining my own BranchGroup and TransformGroup subclasses (using the same names as in Java3D APIs) that set the capability whenever an object is constructed - this way I can simply delete my classes once I don't need to display the tree.)

Note 2: To run the zipped project in Eclipse you'll need to update the "Libraries" in "Java Build Path" within the project's "Properties" and add the correct paths to the external JAR files j3dcore.jar, j3dutils.jar and vecmath.jar. E.g., on my computer the Java3D installer put these files into C:\Program Files\Java\jdk1.6.0_02\jre\lib\ext\. Also, you need to set the applets' parameter "image" to "resources/earth.jpg" and for the second applet also the parameter "greetings" to some text, e.g., "Mele Kalikimaka,Hauoli Makahiki Hou,Merry Christmas,Happy New Year,Veselé Vánoce,Štastný Novy Rok,Feliz Navidad,Prospero Nuevo Año".

Note 3: You may also make sure that also the files j3dcore-d3d.dll, j3dcore-ogl.dll, j3dcore-ogl-cg.dll, and j3dcore-ogl-chk.dll are accessible - on my computer, they are in the C:\Program Files\Java\jdk1.6.0_02\jre\bin folder.


Custom Look and Feel

Since Swing is all implemented in Java, it allows you to customize almost all aspects of the entire appearance and behavior of GUI widgets. While such customization is not very simple to implement within the GUI framework, it is a quite powerful concept. All the properties that govern the visual appearance of a widget are stored in a Hashtable "database" and can be easily modified. (Provided, of course, that you know how.) But there is a more radical option - you can completely redefine how an entire class of widgets appears on the screen and how it behaves! The look_n_feel applet shows you how - it redefines the look of three standard widget classes: the buttons have a rainbow color background whose spectrum shifts when you depress and release them, the text area has a light rainbow color background, and the "thumbs" of scroll bars feature a rainbow color pattern as well.

The applet's main class RainbowLookAndFeelDemo.java establishes the new "rainbow" look & feel which is defined in RainbowLookAndFeel.java. The look of a JTextArea is defined in RainbowTextAreaUI.java, the look of a JScrollBar in RainbowScrollBarUI.java, and the look of a JButton in RainbowButtonUI.java. The common task of filling a rectangle with a rainbow pattern is accomplished in Utilities.java. (Notice that our new view of buttons need few extra properties.)

As a bonus, the applet displays all the properties of Swing's look & feel in a scrolling text area.

These are the resource files of this applet::