JFC vs. AFC: Which Foundation Is for You?
Peter Haggar, IBM
Abstract
Although the Java Abstract Window Toolkit (AWT) is a good first
step toward creating a truly cross-platform GUI class library, the need is
great for a more robust graphical user interface (GUI) class library that
GUI developers can rely on to create leading applications.
In order to solve some of AWT's problems, two new class libraries have emerged:
the Java Foundation Classes (JFC) from JavaSoft and the Application Foundation
Classes (AFC) from Microsoft. Which one prevails will depend on the quality,
features, and, ultimately, the acceptance of each respective library in the
industry.
The Java AWT represents Java's first attempt at a
cross-platform GUI class library. Creating a truly cross-platform
GUI class library is a daunting task and not one likely to be
perfected the first time around. Although the AWT is a good first
step, the need is great for a more robust graphical user interface
(GUI) class library that GUI developers can rely on to create
leading applications.
Two new class libraries have emerged that are attempting
to solve some of AWT's problems: the Java Foundation Classes (JFC)
from JavaSoft and the Application Foundation Classes (AFC) from
Microsoft. Which one prevails will depend on the quality, features,
and, ultimately, the acceptance of each respective library in
the industry.
Introduction
One of the problems with the AWT stems from its design
goals. The goal of the AWT is a cross-platform GUI library that
uses the native windows and controls on the application's run-time
platform. Implementing a library using the native windows and
controls has its benefits. Since it uses native controls, the
AWT provides a familiar look and feel to the applet or application,
no matter which platform the code is running on. However, there
are some drawbacks to this approach. The most notable drawback
is referred to as the "lowest common denominator" problem.
Since the AWT is written using native system windows and controls,
the functionality is minimal since it has to span multiple platforms.
This is because the interface represents the common services that
can be used across the many platforms Java supports. If a feature
is to be included in the AWT that is not on all platforms the
AWT supports, the AWT must provide that support via an emulation
layer. This emulation layer is necessary if the promise of "Write
Once, Run Anywhere" is to be realized.
The industry recognized the problems related with
the native, or peer-based, window toolkit strategy employed by
the AWT. Some leading industry vendors set out to solve this problem
with their own class libraries. Two Java class libraries emerged
from this work: Netscape's Internet Foundation Classes (IFC) and
Microsoft's Application Foundation Classes (AFC).
IBM, Netscape, and JavaSoft agreed to work together
and leverage Netscape's IFC technology (available since 12/11/96)
to produce the JFC. This cooperation between leading industry
partners thrust JFC to the forefront in the GUI class library
battle. The two foremost GUI class libraries are now the JFC from
JavaSoft and the AFC from Microsoft.
Background of AFC and JFC
April 2, 1997, was a big day for Java GUI class libraries.
Both Microsoft and JavaSoft announced competing libraries during
the JavaOne developer conference in San Francisco, California.
Microsoft announced the availability of a preview release for
AFC. AFC was originally announced in January, but this was the
first time code for it had been delivered. Meanwhile, JavaSoft
announced that they were working with IBM and Netscape to produce
the JFC. A preview release of JFC is available now on JavaSoft's
Web site: http://www.javasoft.com. AFC is available from Microsoft's
Web site as part of their SDK 2.0. See: http://www.microsoft.com/java.
Both technologies provide advanced user interface features and
lay to rest the claim that you must "dumb down" interfaces
for cross-platform and Web applications. This "dumbing down"
had been the mantra of some critics of the AWT.
Each of these libraries is written to support what
are called peerless, or windowless, components. This means the
user interface controls are drawn by the library itself, not by
the system the application is running on. The result is that the
user interface and behavior of the application will be the same
on any platform the code is running on. Since these libraries
don't use any native windows or controls, but implement them internally,
they are not bound to the user interface features of the platform.
Some people would also argue that this common look
and feel is the future of user interfaces, and that the AWT style
native look and feel is a thing of the past. I think that as the
platform on which you are running your applications becomes less
and less relevant, the common look and feel employed by AFC and
JFC will be the norm. If Java becomes as ubiquitous as we hope,
I would like to see the same user interface and look and feel
to my applications whether I am accessing them from a PC running
NT or OS/2, a Macintosh, a Network Computer (NC), or a Personal
Digital Assitant (PDA).
Microsoft's Application Foundation Classes
When discussing the AFC, many people are referring
to the GUI class library portion. Actually, AFC is a little more
than that. AFC contains the following packages:
- com.ms.ui-user interface controls. (Typically,
when people talk about AFC they are referring to the functionality
in this package.)
- com.ms.fx-a graphics package. This package contains
Java classes for the manipulation of graphics, fonts, and text.
- com.ms.ui.event-an event handling package. This
package contains support for the Java 1.1 event model.
- com.ms.ui.resource-resource files. This package
contains support for Win32 resource files in Java applications.
- com.ms.util.cab-CAB files. This package contains
support for cabinet (CAB) file creation and extraction.
Most of the discussion in this section focuses on
the user interface aspects of the AFC.
AFC Overview
The AFC class library is a high-level framework for
Java application development. AFC is written entirely in Java,
which means it will run cross-platform on any Java-compliant Virtual
Machine, including browsers. The AFC provides a component model,
similar to AWT's, featuring components, containers, and layout
managers.
Two design features of the AFC are the use of lightweight
classes and peerless, or windowless, components. The AFC does
not directly extend the AWT Component class. The AFC designers
thought that this class was too "heavy." So AFC includes
its own UIComponent class that supposedly uses less memory
than its AWT Component equivalent. The decision to not
extend the AWT Component class affects AFC's compatibility
with the AWT. See the AFC/AWT Compatibility
section below.
Since AFC components do not use any native code on
the system on which they are running, AFC provides a cross-platform
and portable library with a common look and feel. The look and
feel of an AFC application will remain the same as it is moved
to different platforms. The AFC does use the AWT for base frame
and dialog windows. These windows are wrappered with the AFC's
compatibility classes, which are prefixed with AwtUI.
AWT compatibility classes will be discussed in more detail below.
AFC supports the Win32 resource format, allowing
developers to use existing Win32 resources in AFC Java applications.
This support has the added benefit of providing NLS support in
the manner of Win32's support.
AFC supports both the 1.0.2 and the 1.1 event models,
albeit in different ways. AFC applications can only support the
event model supported by the JVM they are using. However, AFC
components can use either the 1.0.2 or the 1.1 event model. AFC
components implement both event models internally. However, the
interface is slightly different from the AWT interface. See AFC
Programmability below.
JavaBeans Support
The standard AFC components such as UIPushButton,
UIRadioButton, etc., are not JavaBeans. The JavaBeans support
with AFC is limited to the AwtUI* compatibility
classes. This means that, in order to use AFC components as JavaBeans,
they must be wrappered with these compatibility classes. This
limits the effectiveness of AFC applications in which JavaBean
support is required.
AFC User Interface Features
AFC provides a solid set of user interface controls
with which Win32 programmers will be familiar. All of the major
Win32 controls are provided as part of the AFC com.ms.ui package,
in addition to a few new features. With the addition of the AwtUI
and UI prefixes, many of the class names will look
familiar to Win32 programmers.
The UI prefix is used for standard
AFC user interface classes. The AwtUI prefix is
used to denote the class that is an AWT compatibility class. This
is provided as a means for using an AFC control in an AWT window.
More information on this subject can be found in the AFC/AWT
Compatibility section. Table 1 provides a list of many
of the AFC user interface controls and their AWT-compatible counterparts.
Control | AFC Class Names
| AWT Compatibility Names |
Button | UIPushButton, UIRadioButton, UICheckButton
| AwtUIPushButton, AwtUIRadioButton, AwtUICheckButton
|
Choice | UIChoice, UIList |
AwtUIChoice, AwtUIList |
Menu | UIMenuButton, UIMenuList, UIMenuItem
| AwtUIMenuList |
Static | UIText, UIGraphic, UIItem
| AwtUIText, AwtUIGraphic |
Edit | UIEdit | AwtUIEdit
|
Scrollbar | UIScrollBar |
AwtUIScrollBar |
Bandbox | UIBand, UIBandBox
| AwtUIBand, AwtUIBandBox |
Status | UIStatus, UIProgress
| AwtUIStatus, AwtUIProgress |
Tree | UITree | AwtUITree
|
Viewer | UIScrollViewer, UIColumnViewer, UISplitViewer, UITabViewer, UIMarquee
| AwtUIScrollViewer, AwtUIColumnViewer, AwtUISplitViewer, AwtUITabViewer, AwtUiMarquee
|
Tip | | AwtUITip
|
Dialog Box | UIPropertyPage, UIWizardStep
| AwtUIMessageBox, AwtUIPropertyDialog, AwtUIWizard, AwtUIFindReplaceDialog
|
Table 1. Many of the AFC user interface controls
and their AWT-compatible counterparts.
Some AFC features of which to take note are HotTracking and BandBox.
HotTracking is a feature which enables controls to change their
appearance when the mouse is over them. This lets the user know
when the mouse is in a position to interact with the underlying
control. The appearance change in the control can be in the form
of one of the following:
- text change
- background color change
- image change
- control outline change (from flat to raised)
The BandBox control is typically used to create a sizable toolbar.
Sets of controls can be added to a UIBand object; then
the UIBand objects can be added to the bandbox. UIBandThumb
objects are then added to the bandbox, allowing the user to size
and position each band.
AFC Layout Managers
The AFC adds a number of new layout managers while supporting
most, but not all, of the existing AWT layout managers. There
are AFC equivalents for FlowLayout, BorderLayout, and GridLayout
called-not surprisingly-UIFlowLayout, UIBorderLayout, and UIGridLayout.
There are no equivalents for Card and GridBag layouts. Therefore,
these layouts cannot be used in an AFC container. The new layout
managers added by AFC are BarLayout, FixedFlowLayout, VerticalFlowLayout,
RowLayout, SplitLayout, TabLayout, TabListLayout, ThreePanelLayout,
and TreeLayout.
AFC/AWT Compatibility
Since AFC does not directly extend the AWT component architecture,
developers cannot freely mix AWT and AFC components in an application.
In order to provide compatibility with the existing AWT, AFC employs
what it calls the AWT compatibility classes. (These are the classes
with the AwtUI prefix.) These classes serve as a
bridge between AWT containers and AFC components. In other words,
if you want to include any AFC components in AWT containers (for
example, an AWT Frame) you must use the AwtUI* classes,
not the standard UI* classes. I see this design
as a major drawback to using AFC. See AFC Programmability below
for additional details.
AFC Programmability
In preparation for writing this paper, I installed the Microsoft
Visual Studio and the SDK for Java 2.0 Beta 2. I then wrote some
AFC code to get a look at how the platform was put together and
what it had to offer. The main problem is the fact that AFC does
not extend directly from the AWT. This is a problem when trying
to mix AFC and AWT components in the same container, because this
mixing requires the AWT compatibility classes. This problem makes
programming the AFC somewhat non-intuitive. In addition, since
AFC, AWT, and AWT-compatible components cannot be easily mixed,
developers need to be acutely aware of with what type of panel
they are working when coding. The following lists show what is
and isn't allowed when trying to mix AWT components, AFC components,
and AWT compatibility components in AWT containers, AFC containers,
and AWT compatibility containers.
In an AWT container (for example, Panel):
- You can embed standard AWT components (for example, Button).
- You cannot embed standard AFC components. For example, you
cannot include a UIPushButton in an AWT container.
- In order to embed AFC components, you need to use the AWT
compatibility classes. For example, in an AWT container, you would
use an AwtUIPushButton, not a UIPushButton.
In an AFC container (for example, UIPanel):
- You can embed standard AFC components (for example, UIPushButton).
- You cannot embed any standard AWT components (for example,
Button).
- You cannot embed any AWT compatibility components (for example,
AwtUIPushButton).
In an AWT compatibility container (for example, AwtUIPanel):
- You can embed standard AFC components (for example, UIPushButton).
- You can embed AWT compatible components (for example, AwtUIPushButton).
- You cannot embed any standard AWT components (for example,
Button).
The major drawback here is that in order to use any AFC components
in any AWT containers, one must use the AWT compatibility classes,
not the standard AFC classes (See Listing 1). When using AFC containers,
developers are limited to only standard AFC components and cannot
use any AWT components (See Listing 2). In addition, when using
an AWT Compatible container, standard AWT components cannot be
included (See Listing 3).
I found myself continually going back to the documentation to
see if I were using the correct class. For example, if I wanted
to put a button in a container, did I need to use UIPushButton,
AwtUIPushButton, or Button? Well, that depends on the type of
container one is using. This made coding the AFC particularly
irritating.
class AWTButtonDemoPanel extends Panel
{
AWTButtonDemoPanel()
{
Button AWTButton = new Button("AWT button");
AwtUIPushButton AWTUIPushButton = new AwtUIPushButton("AwtUIPushButton");
UIPushButton AFCUIPushButton = new UIPushButton("AFCUIPushButton");
add(AWTButton); //OK...standard AWT component
add(AWTUIPushButton); //OK...AFC button used in AWT wrapper
add(AFCUIPushButton);
//Compile error! Will not compile since AWT Panels don't
//know anything about AFC components
}
}
|
Listing 1: AWT Container and AWT, AFC, and AWT compatibility components.
class AFCButtonDemoPanel extends UIPanel
{
AFCButtonDemoPanel()
{
UIPushButton UIPushButton = new UIPushButton("AFC UIPushButton");
AwtUIPushButton AWTUIPushButton = new AwtUIPushButton("AwtUIPushButton");
Checkbox AWTCheckBox = new Checkbox("AWT Checkbox");
add(UIPushButton); //OK...standard AFC Component
add(AWTUIPushButton);
//Compile Error! Will not compile since UIPanel does not
//support the AwtUI* compatibility classes.
add(AWTCheckBox);
//Compile error! Will not compile since UIPanel does not
//support standard AWT components.
}
}
|
Listing 2: AFC Container and AFC, AWT compatibility, and AWT components.
class AWTCompatibleDemoPanel extends AwtUIPanel
{
AWTCompatibleDemoPanel()
{
UIPushButton UIPushButton = new UIPushButton("AFC UIPushButton");
AwtUIPushButton AWTUIPushButton = new AwtUIPushButton("AwtUIPushButton");
Checkbox AWTCheckBox = new Checkbox("AWT Checkbox");
add(UIPushButton); //OK
add(AWTUIPushButton); //OK
add(AWTCheckBox);
//Compiles OK! However, throws IllegalArgumentException
//at runtime. Parameter to add must be a subclass of
//AwtUIControl.
}
}
|
Listing 3: AWT Compatible container and AFC, AWTUI*-compatible, and AWT components.
Another cause for irritation is the event model interface in AFC.
For example, instead of implementing the ActionListener
interface as you would in AWT or JFC, you must implement the IUIActionListener
interface. Instead of overriding the public void actionPerformed(Action
event); method as you would in AWT or JFC, you override
the public void actionPerformed(UIActionEvent event)
method. The same holds true for the other event classes. All of
the AFC event and listener classes are prefixed with UI
. Another weakness is that AFC does not support the adapter classes.
The adapter classes are convenience classes that the AWT employed
in the 1.1 event model to make programming the new event model
easier. None of this is very surprising once you understand the
design of the AFC library, but it makes it annoying to program
if you already know the AWT 1.1 event model.
JavaSoft Java Foundation Classes (JFC)
JavaSoft's JFC has been positioned as the main alternative
to Microsoft's AFC. The battle has been escalated by the fact
that Microsoft has stated that they will not ship the JFC library
with their JVM. This means that for JFC applications to run on
Microsoft Windows platforms, they will need a Windows JVM other
than Microsoft's.
JFC was born out of Netscape's work on their IFC
library. Sun, Netscape, and IBM have teamed up to produce the
JFC, which will ship with JDK 1.2. When people speak of JFC, they
often are referring only to the user interface components contained
in JFC, commonly referred to as Swing or SwingSet.
JFC contains the following:
- High level UI components-Swing
- 2-D Graphics
- Drag and Drop
- Pluggable Look and Feel
- Accessibility Features
JFC Overview
The JFC is designed so that it is a superset of the
AWT. In other words, JFC extends directly from the AWT to add
many new components and services. All of the new components in
JFC extend directly from the AWT Component class. This
makes JFC fully compatible with AWT- based applications.
Two of the JFC design features are equivalent to
the design features of AFC. The JFC uses lightweight classes and
peerless, or windowless, components. Also, it does not use any
native code when drawing its components. This allows JFC to provide
a cross-platform and portable library with a common look and feel.
Additionally, JFC provides what is called Pluggable Look and
Feel, which provides the ability to change the look and feel
of an application dynamically.
To run JFC applications, the JDK 1.1.2 or higher
is required. Because of this, JFC supports only the 1.1 event
handling model.
JavaBeans Support
All JFC components are written as JavaBeans. This
gives developers of JFC applications all the benefits of JavaBeans
with their JFC components.
JFC User Interface Features
JFC provides a rich set of user interface components
to enhance GUI applications. All of the existing AWT components
are provided, in addition to many new high-level components. To
distinguish between standard AWT classes and JFC classes, all
JFC classes are prefixed with a "J". See
Table 2 for a list of the new high-level components.
Tree View | Slider
| Menus | Properites |
List View | Styled Text |
Status Bar | AudioGauge |
Table View | Font Chooser |
SpinBox | MidiPanel |
Toolbar | Color Chooser |
ComboBox | MovieController |
Pane Splitter | File Chooser
| Dropdown ComboBox | AudioController
|
Tabbed Folder | Custom Cursors
| ProgressBar | MovieSlider |
Multi-Column list | Tool Tips
| Buttons | |
Table 2. The new high-level components.
One very useful and unique feature of the JFC is the DebugGraphics
option. The DebugGraphics feature is a tool you can use to test
whether your components are being drawn correctly. With DebugGraphics,
you can highlight the component parts in bright red as they are
being drawn. This allows you to view them as they are being drawn
and to observe exactly how all drawing operations are taking place.
Another major user interface feature of JFC is Pluggable Look
and Feel, which provides the ability to change the user interface
of a set of components (for example, all buttons) or the entire
application dynamically at run time. To support this feature,
JFC application developers do not need to subclass the entire
JFC component set.
JFC Programmability
I downloaded the 1.1.3 version of the JDK and the JFC code from
the JavaSoft Web site and started to program with it. I used my
AWT skills to begin programming in JFC immediately. Working with
existing AWT classes in the JFC was a snap. You simply need to
prefix the class name with a "J". So,
if you want a JFC button, you code JButton. If you want
an AWT button, you simply code Button. You also don't have
to worry about mixing JFC and AWT components and containers. They
all work together seamlessly, making it easy to mix JFC and AWT
code.
JFC Layout Managers
JFC supports all of the existing AWT layout managers and also
adds a new one. The new layout manager is called SpringLayout.
The SpringLayout allows you to define which spaces should change
size when a component is sized. The defined spaces are: left margin,
right margin, top margin, bottom margin, width, and height. Each
of these spaces can either be a spring or a strut. A spring is
a flexible space and can grow during sizing. A strut is an inflexible
space and, whenever possible, it does not change size.
JFC/AWT Compatibility
JFC was designed to be fully compatible with the AWT. Therefore,
you do not need to concern yourself with mixing separate Component
models. This compatibility will be critical as people begin to
use new JFC applications with existing AWT code.
AFC/JFC Performance Comparison
To compare the performance, I first wrote an application
using JFC (see Appendix A). This application allows you to create
a frame window with a panel containing a user-specified number
of buttons. The application measures three aspects of performance:
- creation time of the frame with the buttons
- layout time of the buttons
- paint time of the buttons
Once I had the application working properly under
JFC, I block-copied the code into Microsoft Visual Studio and
converted it to be run with AFC (see Appendix B). This conversion
was very simple and straightforward. The design of the application
did not have to change-only the class names being used were changed.
When I got a clean compile, the AFC program worked properly the
first time. I then had identical applications for both JFC and
AFC with which to run my tests.
Both programs employed identical designs. I overrode
the paintAll() and layout() methods
to capture the paint and layout timings (in the JFC code, I actually
overrode doLayout() since layout()
was deprecated for 1.1). The code was compiled and run with the
following setup for JFC:
- JDK 1.1.3
- JFC Swing 0.3 developers' preview release
For AFC:
- Microsoft Visual Studio
- SDK for Java 2.0 Beta 2
Before I actually looked at the numbers, I noticed
that JFC seemed to be much faster than AFC. The performance numbers
supported this observation. See Table 3 for the actual numbers.
All times were gathered using the System.currentTimeMillis()
call. I ran the creation time scenario numbers, creating 100 and
500 buttons. The layout and paint times were both done only for
100 buttons. The numbers are an average of five samples I took
for each test.
All of the performance measurements were generated
on an unloaded 133MHz Pentium processor machine with 80MB of memory
running Window NT 4.0. In addition, each application was built
with the -O option indicating full optimization of the
code.
Activity | AFC average time in milliseconds
| JFC average time in milliseconds
|
Create 100 Buttons | 1,692 |
592.6 |
Create 500 Buttons | 6,895.8
| 3,072.8 |
Layout | 326.4 | 96.2
|
Paint | 478.8 | 382.4
|
Table 3. AFC performance versus JFC performance.
As you can see, JFC easily outperformed AFC in each category-and
by a wide margin. More specifically, JFC performed 185% faster
creating 100 buttons, 124% faster creating 500 buttons, 239% faster
during layout, and 25% faster painting the buttons.
Both libraries exhibited painting problems and unnecessary multiple
paints and layouts, but I would not expect much more from Beta
code. Improvements will be made to both libraries as time goes
by, but JFC has a clear performance advantage, which AFC will
have to work very hard to match, let alone eliminate.
AFC/JFC Feature Comparison
Table 3 is a list of the major differentiating features
between AFC and JFC. I have indicated the feature and noted the
support each library gives the feature. I have then indicated (in bold CAPS),
where appropriate, which library has a better implementation and,
therefore, a competitive advantage based on the implementation
of the feature.
Feature
| AFC | JFC
|
100% Pure Java | Yes
| Yes |
Pluggable L&F | No
| YES |
Peerless Components | Yes
| Yes |
Lightweight Comp | Yes
| YES |
JavaBeans support | Limited
| FULL |
1.0 Event Model | YES
| No |
1.1 Event Model | Yes
| YES |
Drag/Drop | No
| YES |
Printing | No
| YES |
Win32 Resource files | YES
| No |
2D Graphics | Yes
| Yes |
AWT Compatibility | Limited
| EXCELLENT |
Programmability | Fair
| EXCELLENT |
Performance | Poor
| GOOD |
Table 3. Comparison of AFC and JFC features.
And the Winner Is....
Based on the facts uncovered during my examination
of these two class libraries, JFC is the clear winner. JFC is
better designed, has more features, and is easier to use than
AFC. Each one has a few features the other does not, but AFC lacks
the more important features that JFC provides. Strong AWT compatibility,
Drag/Drop, and Printing are three features AFC does not have and
needs in order to be considered a serious contender.
In areas in which they both provide the same feature,
the JFC implementation and support are typically much better than
AFC. For example, JFC does a much better job with JavaBeans, general
programmability, and the 1.1 event model. In addition, the performance
of the JFC was far superior to AFC, giving the JFC a big edge
in this important category.
JFC is a more solid foundation on which build Java
applications. It was clear in using JFC that the designers intended
little to no impact on current AWT programmers moving to the JFC.
Appendix A
//JFC Performance measurement application
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
class JFCButtonFrame extends Frame implements ActionListener
{
private JButton repaintButton;
public JFCButtonFrame(JFCPerfFrame perfFrame, int numButtons)
{
setTitle("JFC Button Panel");
setLayout(new BorderLayout());
JFCButtonPanel buttonPanel = new JFCButtonPanel(perfFrame, numButtons);
add(buttonPanel, "Center");
JPanel timePanel = new JPanel();
repaintButton = new JButton("Repaint");
repaintButton.addActionListener(this);
timePanel.add(repaintButton);
add(timePanel, "South");
class JFCButtonFrameAdapter extends WindowAdapter
{
public void windowClosing(WindowEvent event)
{
dispose();
}
}
addWindowListener(new JFCButtonFrameAdapter());
}
public void actionPerformed(ActionEvent event)
{
if (event.getSource() == repaintButton)
{
paintComponents(getGraphics());
}
}
}
class JFCButtonPanel extends JPanel
{
private JFCPerfFrame perfFrame;
public JFCButtonPanel(JFCPerfFrame f, int numButtons)
{
perfFrame = f;
setLayout(new FlowLayout());
for (int i=0; i
Appendix B
//AFC Performace measurement application
import com.ms.ui.*;
import com.ms.fx.*;
import com.ms.ui.event.*;
import java.awt.*;
import java.awt.event.*;
class AFCButtonFrame extends AwtUIFrame implements IUIActionListener
{
private UIPushButton repaintButton;
public AFCButtonFrame(AFCPerfFrame perfFrame, int numButtons)
{
setTitle("AFC Button Panel");
setLayout(new UIBorderLayout());
AFCButtonPanel buttonPanel = new AFCButtonPanel(perfFrame, numButtons);
add(buttonPanel, "Center");
UIPanel timePanel = new UIPanel();
repaintButton = new UIPushButton("Repaint", UIPushButton.RAISED);
repaintButton.addActionListener(this);
timePanel.add(repaintButton);
add(timePanel, "South");
}
public void actionPerformed(UIActionEvent event)
{
if (event.getSource() == repaintButton)
{
paintComponents(getGraphics());
}
}
public boolean handleEvent(Event evt)
{
switch (evt.id)
{
case Event.WINDOW_DESTROY:
dispose();
return true;
default:
return super.handleEvent(evt);
}
}
}
class AFCButtonPanel extends UIPanel
{
private AFCPerfFrame perfFrame;
public AFCButtonPanel(AFCPerfFrame f, int numButtons)
{
perfFrame = f;
setLayout(new UIFlowLayout());
for (int i=0; i
|