Experimenting with Swing Application Framework
Join the DZone community and get the full member experience.
Join For FreeThe quality and speed of building a Java-based graphic user interface (GUI) have always been high on the agenda. It is no secret that the development of a graphical interface using Swing requires quite a plenty of time. But it’s not critical if the developer doesn’t have a very deep knowledge of a GUI building. He just needs to write large amounts of code for the creation and adjustment of any graphical component. Sometimes this process becomes quite monotonous and boring and it’s great when you can delegate this routine work with component adjustment to anybody else…
Swing Application Framework library is designed to help with the development of desktop applications that contain GUI. It’s a small set of Java classes, aka “the framework”, that provides a ready-to-use infrastructure for most desktop applications. The use of this library allows to make an application architecture more obvious, and the code “lighter” for understanding and further support. Besides this framework undertakes all the routine operations with the configuration of graphical components, and lets the developer to concentrate on other aspects of application development (realization of business logic etc.).
For each of our products we create a demo application to highlight its major features. For our new product, JxCapture, we also made a small demo application which in fact represents a simple screen capture solution. It’s a common Swing application. The functionality of the application is enabled through a menu accessible through a tray icon, providing settings and an image viewer for a captured image.
Initially, we implemented the demo application using a standard Java Swing library. However, we are always on the look for new ways and technologies that can help us make our products better. Keeping track of the development of the Swing Application Framework, that is designed to help with the desktop application development, we decided to try it out and re-write the existing Swing-based application. The purpose of this “experiment” was to research the capabilities of the framework and possibly to further use it in the development of Java-based desktop applications.
So we had a Swing-based application and decided to write exactly the same one but with the Swing Application Framework.
Application Lifecycle
When we started working we noticed at once how convenient application lifecyle was realized. Swing Application Framework provides a very convenient mechanism for tracking of such events like starting and shutting down an application. For application start we realized all the necessary operations, such as reading of application settings from a configuration file, registration of various listeners, adjustment of graphical components of an application etc.
At application shutdown we carry out all necessary operations required for a correct shutdown: releasingof unused resources, closing streams, removing listeners, saving settings into configuration file.
To launch our application we just needed to inherit the main class of an application from the SingleFrameApplication and to call Application.launch function in the main method. We had no need to wrap the code that launches the application into Event Dispatch Thread. This functionality was already realized in the function Application.launch.
public static void main(String[] args) throws Exception {
launch(JxCaptureDemo.class, args);
}
We were pleasantly surprised that the default look and feel was system-dependant.
Resources
The application framework supports automatically initializing the properties of named components from ResourceBundle resources. That is using “resource injection” we can adjust many parameters of the component simply by naming it! All other parameters that are defined in the appropriate resource file will be set automatically.
We used this mechanism when configuring all graphical components of our application. For example in the dialog “About” we used “resource injection” to adjust most of the components of this dialog. Parameter values for components reside in a special resource file—AboutDialog.properties. This approach is especially convenient for a mixed-language interface. Besides all the data for the graphical components is stored in one place what simplifies the search and replacement of any parameters.
Resources can be used for initialization of class fields as well as for adjustment of component parameters. We just needed to mark required fields with annotation @Resource and to set values in the properties file for these fields. After the command ResourceMap.injectFields was executed all the marked fields were initialized automatically. In most cases the fields were of a simple type (String, int etc.). But in the class ApplicationSettings we used this approach for initialization of fields that represent string arrays. For this purpose we only needed to determine in the properties file the following content:
ApplicationSettings.imageFormats[0] = png
ApplicationSettings.imageFormats[1] = jpeg
ApplicationSettings.imageFormats[2] = bmp
ApplicationSettings.imageFormats[3] = gif
And in the class ApplicationSettings we also needed to make initialization that had the following look:
public final class ApplicationSettings {
@Resource
private String[] imageFormats;
// ...
private ApplicationSettings() {
ApplicationContext context = Application.getInstance().getContext();
ResourceMap resourceMap = context.getResourceMap(ApplicationSettings.class);
imageFormats = new String[resourceMap.getInteger("ApplicationSettings.imageFormats.length")];
resourceMap.injectFields(this);
}
// ...
}
As you can see we had to allot memory for the field imageFormats before initializing this field. It’s a little bit unhandy, because we have to know the exact number of array components. In our case we decided to store the array length in the resource called “ApplicationSettings.imageFormats.length”. Hopefully developers will make memory allotment as a part of the field injection in the future.
Actions
Every desktop application is based on an event model. Using the annotation @Action in SAF we can mark a method that’s intended to serve as the implementation of an Action’s actionPerformed method. The ApplicationContext getActionMap method creates an ActionMap that contains one Action object for each @Action defined by some class. The annotation @Action in our code lets us make it more obvious and easy for perception. So, for example, the realization of events in the class TrayPopupMenu with SAF has the following look:
public class TrayPopupMenu extends JPopupMenu {
private ApplicationSettings settings = ApplicationSettings.getInstance();
private CaptureOperations operations = CaptureOperations.getInstance();
private boolean captureOperationEnabled = true;
// ...
public boolean isCaptureOperationEnabled() {
return captureOperationEnabled;
}
public void setCaptureOperationEnabled(boolean captureOperationEnabled) {
boolean oldValue = this.captureOperationEnabled;
this.captureOperationEnabled = captureOperationEnabled;
firePropertyChange("captureOperationEnabled", oldValue, this.captureOperationEnabled);
}
@Action (enabledProperty = "captureOperationEnabled")
public void activeWindowCapture() {
operations.activeWindowCapture();
}
@Action (enabledProperty = "captureOperationEnabled")
public void objectCapture() {
operations.objectCapture();
}
// ...
}
The realization of the same class using a standard approach requires 30% more code lines! The parameters for each event we described in the appropriate properties file:
activeWindowCapture.Action.text = Capture active window
activeWindowCapture.Action.icon = images/act_window.png
activeWindowCapture.Action.accelerator = control shift A
objectCapture.Action.text = Capture window / object
objectCapture.Action.icon = images/win_obj.png
objectCapture.Action.accelerator = control shift W
...
These @Actions also introduces the enabledProperty annotation parameter which binds the enabled state of the @Action to the current value of a property. Our application settings allow to set assignable delay before capture operation, so that the user could take some actions before this operation takes place, for example he can open/close some windows. It’s advisable to restrict the for the user from performing other operations during this delay. It can be realized for example by disabling them. In our example we have just that case.
The parameter captureOperationEnabled checks if any operation is currently launched. Thanks to the entry @Action (enabledProperty = "captureOperationEnabled") we bind the state of the variable captureOperationEnabled to the state of an event (in our case to the state of all the events that should be disabled when there is already one operation running). It’s very convenient and easy!
Unfortunately it’s possible to define only the method that determines the realization of Action’s actionPerformed method so far. It would be very convenient if we could define parameterized events using annotations. And until then we have only one solution for such cases—to use standard Swing approach which is based on creation of a class that will describe the required event.
Summary
In our application we had no need to use other features of this framework, such as:
- Persistent session state: support for automatically and selectively saving GUI state, like top level window geometry, from one run of an application to the next.
- Actions that swap background tasks.
But I’m sure these features will be useful in most desktop applications. This framework is certainly worth using in development of large applications. In most cases Swing Application Framework contains everything that experienced developers may need for their complex applications (application lifecycle, task service or resource management). And even if there’s missing something here, you can always use standard approach.
In whole in spite of some shortcomings mentioned above (or peculiarities if we can say so :-), it was very interesting and easy to re-write with Swing Application Framework an application primarily written using Swing. This framework has a lot of really convenient and practical things. Sometimes its approaches seem to be so obvious that it’s strange that nobody has implemented it earlier. So, long live developers of this framework! They managed to enhance the development process for desktop applications in Java and to make it more interesting and convenient.
Useful Links
- Swing Application Framework site
- JxCapture Demo: SAF and Swing versions
- JxCapture Demo sources: SAF and Swing version
Opinions expressed by DZone contributors are their own.
Trending
-
Event-Driven Architecture Using Serverless Technologies
-
Introduction to Domain-Driven Design
-
RBAC With API Gateway and Open Policy Agent (OPA)
-
Tech Hiring: Trends, Predictions, and Strategies for Success
Comments