JFC vs. AFC: Which GUI toolkit should you use?

An objective, in-depth, technical comparison of both technologies -- from a developer's perspective. Plus: a step-by-step guide to running AFC apps using Sun's JDK 1.1

The foundation class sets in the Java world have evolved rapidly in the past year. JavaSoft's Java Foundation Classes (JFC), succeeding the JDK's Abstract Windowing Toolkit (AWT) and Netscape's Internet Foundation Classes (IFC), has taken on the mission to continue battling Microsoft's Application Foundation Classes (AFC). JFC is released as a separate collection of packages designed to work smoothly with JDK 1.1; these packages will be making their way into the core of Java as integral part of JDK 1.2. AFC, taking great pains to be backward-compatible with JDK 1.0, can work impressively with JDK 1.1; and its design and implementation technically doesn't prevent it from being upward-compatible with future JDK releases. We consider both AFC and JFC to be very promising. They are both here to stay.

Many developers are wrestling with the question of which technology to use in their application development. It seems JFC and AFC have divided the world of Java graphical user interfaces (GUIs) into two camps. Putting aside the political issues, marketing hype, and personal religions, this article offers a comprehensive examination and comparison of JFC and AFC and provides some insight designed to help you choose the GUI toolkit that's best for you.

The basics: AFC and JFC components

JFC consists of five components:

  • AWT
  • Swing (the Java GUI toolset)
  • The Java 2D API
  • The accessibility API
  • A drag-and-drop framework

AFC is Microsoft's alternative to JFC Swing. Its core packages include:

  • UI, an equivalent of JFC Swing and AWT
  • FX, a package that provides improved support on graphics, font and color and some supporting utility classes

Note that drag and drop is not inherent to AFC, but an AFC application can have drag-and-drop capability if the Microsoft Java software development kit (SDK) is being used.

In this article we focus mainly on the comparison between JFC Swing and AFC, although we also will discuss in brief the 2D framework, accessibility, and drag-and-drop features. For convenience, however, in the following text we simply use "JFC" to refer to any subset of JFC.

Design philosophy and general architecture

Both JFC and AFC strive to provide a better GUI framework than the original AWT in JDK. Goals include better performance and a more consistent look and feel across platforms with different Java implementations. Both JFC and AFC have made available a comprehensive set of GUI components sufficient for development of most Java-based GUI applications. JFC and AFC share some similar goals:

  • Lightweight or "peerless" (GUI components that do not have native opaque windows associated with them)
  • High performance
  • Consistent look and feel across platforms
  • Richer set of GUI components with advanced features
  • Pure Java implementation (no native libraries are involved)

Despite these similar goals, AFC and JFC have been designed and implemented with distinctively different architectures:

Sample class hierarchy for AWT, AFC and JFC
  • JFC is based on the JDK 1.1 Lightweight UI Framework, which allows creation of peerless components that fit seamlessly into existing AWT models. JFC components are derived from the AWT Component class. AFC, in contrast, is based on its own lightweight framework -- it has its own class hierarchy that is parallel to JDK AWT's hierarchy. AFC components are not derived from AWT classes.
  • JFC uses strictly the JDK 1.1 delegation event model. AFC supports both JDK 1.0 and 1.1 event models at the API level, but its core implementation of event propagation is completely 1.0-based. We will explain this in more detail in a later section.
  • JFC supports the Model-View-Controller (MVC) architecture and pluggable look and feel. AFC enforces a single Windows look and feel across platforms.

The differences between the AFC and JFC architectures are no surprise. After all, AFC is intended as a replacement of the AWT, though it can accommodate AWT components through special facilities. JFC is an extension of AWT. It follows the AWT architecture, but adds to it the power of MVC and integrates with it the beauty of pluggable look and feel.

Event models and performance

JFC Swing and AFC have different policies on supporting and implementing JDK 1.0 and 1.1 event models. As a result, the performance of these two systems differs considerably.

JFC Swing uses the JDK 1.1 delegation event model exclusively, partially because some of the JFC components use this event model inside their internal implementation. Typically, the look-and-feel implementation class of a JFC component needs to receive events for rendering the component's view correctly to exhibit certain behavior. The class usually registers its related code or even itself as the listener to its corresponding component. That is, communication between the JFC component classes and their corresponding look-and-feel implementation is usually reliant on the delegation event model for event passing. For example, a JFC tree look-and-feel implementation class adds itself as a mouse event listener to the JTree component in order to receive mouse events. Due to the "all or nothing" event processing policy in JDK 1.1 (which determines the event model type of a component and processes all events on that particular component using exclusively the determined model), it is not safe to assume a JFC component can receive and/or propagate 1.0 type of event. To make it clearer, though JFC is extended from JDK 1.1 AWT, which is backward-compatible with the 1.0 event model, the JFC components do not inherit that backward compatibility.

The AFC event model, on the other hand, is a hybrid of both JDK 1.0 and 1.1 models. It provides 1.1 API support on top of a 1.0-model base implementation. Different from the "all or nothing" approach in JDK, AFC propagates all 1.1 events to its containment class in the hierarchy, as if those are 1.0 events.

Developers should be aware that even though AFC provides 1.1 event model API, it does not provide the benefit of the JDK 1.1 event model, which is supposed to eliminate duplicated and unwanted event propagation. Within AFC, we find that a 1.1 event listener registered with a container can possibly be triggered by a 1.0 event originated from a component inside the container. Thus, the application's performance is not only unable to improve, but also likely to become worse if an application mixes both 1.0 and 1.1 event models. In our opinion, the AFC event model has a serious performance hole and doesn't scale up in large applications.

Using exclusively the JDK 1.1 event model, JFC applications can achieve better performance with reduced event traffic. The trade-off with the JFC's approach of supporting only the 1.1 event model, however, is that the event-handling mechanism of all 1.0-compatible applications will need to be modified to upgrade to JFC. On the other hand, AFC provides an easier path for migration of applications using the old 1.0 event model.

A simple application with a button in a Panel of a Frame.

On the right hand side, we illustrate the difference between the AFC and JFC event models. When the button in this application is pressed, AFC applications will make four event related calls, while JFC applications will make only one.

We assume an ActionListener is registered with the button and a MouseListener is registered with the panel.

Event models

AFC event model

(a hybrid of AWT 1.0 and 1.1 event model)

The two postEvent calls propogate

AWT 1.0 MouseEvent from a

component to its container,

and the actionPerformed call

triggers the ActionListener

registered with the button. Note

that the MouseListener registered

with the panel is also triggered

because the panel receives an

AWT 1.0 MouseEvent.

JFC event model

(strictly AWT 1.1 event model)

The ActionListener registered

with the button is called. There is

no other unwanted or duplicated

event propogation.

Extensibility and flexibility

During GUI application development, developers are constantly confronted with two issues:

  • The mechanism of associating GUI front-end prototype with back-end application logic and data
  • The ways of putting existing and derived GUI components together to compose a powerful and impressive user interface

A common development practice that addresses the above two issues is to extend an existing GUI framework to incorporate application logic and then use the extended components as flexible building blocks to build applications. As a result, the extensibility and flexibility of both JFC and AFC is of concern to many developers.

Basically, sub-classing from AFC components or implementing AFC UI interfaces is the only way to extend AFC components. This approach is straightforward. With a lot of important methods opened and implemented in the top-level class of UIComponent, developers should find it easy to derive customized components from UIComponent or its subclasses that work smoothly with the AFC system.

There are three major ways to extend the JFC system:

  • First, if a unique look and feel is desirable, you may choose to either implement the JFC look-and-feel UI framework directly or extend one of the existing look-and-feel implementations.

  • Second, the data structures being used by the JFC components are highly extensible. Each JFC component points to a data-model interface and makes use of a default implementation of that particular interface. Developers can use the default data-model implementation in many cases, but can also extend the default implementation or even provide their own implementation to replace the default version.

  • Third, if a desired component is completely unavailable in JFC and neither of the first two methods helps in any way (i.e., it is impossible to derive such a component through subclassing of existing JFC GUI components) one can work directly on the AWT Lightweight UI framework to create a lightweight component based on the AWT top-level Component class or the JFC Swing top-level JComponent class. After all, the JFC MVC architecture, by detaching the GUI front-end of a component from the application-specific back-end data structure, has greatly reduced the need to derive customized GUI components for application development. In AFC-based or AWT-based application programming, however, the need to derive customized GUI components to incorporate application logic is frequent.

In terms of flexibility, JFC is well known for allowing programmers to fine-tune and switch the data structure of GUI components during development and letting users switch the look and feel in runtime. Considering the absence of MVC and pluggable look and feel in AFC, however, we think it's more appropriate to focus our discussion of this issue on other areas that both toolkits share. One such area is the flexibility of gluing together components to create customized user interfaces. In AFC it's generally possible to add virtually any component as a "child" to any other component. For example, while a simple component like a button or label could be added as a child node to a tree, it's also possible to add a tree as a child component to a button or label. As another example, composite components like list, ComboBox, or even table also could be added as nodes to a tree. The ways of composing components are not strictly defined but left wide open, regardless of whether the composition makes sense. On the other hand, despite the fact that each JFC component is a subclass of AWT Container and therefore can be added programmatically to any other arbitrary JFC component, the process of adding a composite component as a child to a simple component usually yields unexpected results. There are two reasons for this:

  • First, a JFC component always reroutes its repaint request to its look-and-feel implementation class, which makes some assumptions about the contents of the component and renders those contents according to those assumptions.

  • Second, some composite JFC components like JTree and JTable do not contain sub-components directly, but instead use special facilities called Renderer/Editor for data presentation. For example, if you add a JTree to a JButton, JButton's look-and-feel implementation assumes JButton's contents to be text and/or images and will not render the tree for display. For another example, if you add a button as a node to a tree, the button's "look" is preserved but the "feel" -- say, the push-down/pop-up behavior that occurs when the button is clicked -- is lost.

We will not go into detail on the concepts of Renderer and Editor in this article. We will, however, note the difficulty of visualizing a collection of complicated, high-variety data items while using JFC composite components with the Renderer/Editor mechanism. AFC's approach is simpler, more explicit, and more flexible.

Integration with AWT

AFC UI components are not compatible with AWT because they are not derived from the AWT hierarchy. An AFC component cannot be added to an AWT container. (For example, a UIButton can't fit in an AWT Panel.) AFC does, however, provide facilities to allow integration of the two systems. AFC UI components, wrapped by their corresponding AWT adapters, could be easily added to any AWT container. For example, a UIButton, wrapped by its AWT adapter AwtUIButton, could be added to an AWT Panel. AWT components, on the other hand, can also be hosted by an AFC container class UIAwtHost to function properly in an AFC application.

1 2 3 Page 1
Page 1 of 3