JustNuff and GUIs

This article was originally published in VSJ, which is now part of Developer Fusion.
In our daily programming life, there are many situations in which we have to create applications that are not GUI-centric. These are mostly computational, parsing, or processing-intensive applications that need to solicit very limited input from the end user. Historically, these applications request user input via a text-based interface over a telnet-style terminal prompt. Contemporary users, however, are becoming increasingly dependent on the availability of a GUI. This dependency manifests itself in the form of a minimal expectation that if an application has a user interface, it should be a graphical one! In this GUI-everywhere world, command line interfaces are typically associated with ancient legacy software, and these properties are often inferred onto those who create such command-line-based software. To avoid being labelled as an "old world" developer, there is an invisible yet constant pressure to create a GUI, regardless of how trivial the need for one really is. The unfortunate thing, especially for the Java developer, is that the standard Java programming language provides no concrete assistance in doing "just enough" GUI.

This article presents a solution to this problem, in the form of a GUI library called the 'justnuff' library, specifically designed for non-GUI developers. We will first present the design and usage of the library, emphasising the ease of use for those unused to creating GUIs. Next month we'll look under-the-hood and reveal the code of the library, exploring many advanced new Swing-based GUI features, and discuss some interesting techniques for GUI library design.

The virtue of doing justnuff GUI

Essentially, when one is programming in the Java language, one is faced with a dilemma: When Java programming, you're either doing GUI or you're not.

GUI is an all-or-nothing phenomenon in Java programming. This may be attributed to the language's origin as a web page graphical applet creation facility. Both the initial java.awt.* GUI library, and the now standard Java Foundation Classes (JFC or more frequently called "Swing") library has a completely GUI-centric programming view – one that demands a steep learning curve and an even longer mastery cycle.

Figure 1
Figure 1: The GUI-centric model of Java's GUI libraries

In Figure 1, which illustrates the GUI-centric model of Java's GUI libraries, the GUI is the primary focus of application design, and application logic is secondary. The user interacts with the GUI of the application, and events are generated based on the interaction (i.e. user clicks a button or selects a menu item) and are placed into an event queue. This event queue is processed by a single event handler thread (in the case of the older awt library, this is actually co-ordinated through a "peer" object in the host's operating system), and the GUI is updated or certain application logic is executed. Note that while the single event handler thread is performing the application logic, it is not available to update the GUI. This means that any application logic taking a significant amount of time may "lock up" the GUI – making it irresponsive to the user. This further aggravates the already second-class citizen status of application logic in this model. The typical recommendation is to spawn another "application logic thread" to perform any application logic that may require significant processing time. However, for developers who are focused on their application logic, and do not want to spend valuable productive time fiddling around with complex GUI APIs, the operation model depicted in Figure 2 is ideal.

Figure 2
Figure 2: justnuff approach to GUI

In this model of operation, the application logic is taking centre stage. The application logic executes in its own thread, completely free of any GUI encumbrances. When (and only when) it needs to display status to the end user, or to obtain input from the user, it will go to the GUI subsystem to get it done. The GUI system still runs its own event handling thread, but the setup and maintenance (the hard part) is handled by our justnuff library. Whenever the application logic calls for a GUI operation, it will synchronise and wait until that operation is completed. This is done transparently, by the justnuff library. What happens is that an event is queued in the event queue of the GUI subsystem, and the application logic's thread will wait until the event is processed before continuing on. This effectively converts a highly asynchronous and object-oriented GUI subsystem into a synchronous "flat" API – greatly facilitating the "just enough" usage pattern.

Requirements of the justnuff library

In order to make the justnuff library user-friendly, the following are the essential user requirements – adopting the view of a typical non-GUI programmer.

  1. The API library must be easy to learn, use, and master.

    Since mastering sophisticated GUI API programming is not the primary goal in life for our user base, it is unacceptable for the library to take days to learn and master (unlike swing and awt). The goal for the justnuff library is a 5-minute learning curve and one hour to mastery time. This will ensure that our user base can focus on the work at hand and not be distracted by GUI programming details.

    To achieve this requirement, the API must be highly regular and simple to remember. Care must be adopted for API naming, parameterisation, and calling convention. We must not assume any prior swing, awt or GUI programming experience.

  2. All library APIs must be callable from an application logic thread.

    This is obvious from Figure 2. Since the application logic thread must be able to call into the GUI subsystem at any time, without running into potential thread safety problem. This may sound simple, but it turns out that over 97% of the swing's API methods are unsafe to call directly from another thread! Swing is not thread-safe.

    This is the main reason why we need to synchronise the application with the GUI's event handling thread through the event queue in Figure 2. This approach will ensure that any GUI manipulations are always handled by the GUI's one and only event handling thread – thus satisfying the thread-safety requirements of the swing API. This level of complexity must not be exposed to the end user.

  3. The API calls must be stateless.

    Tracking and managing complex GUI states is the main contributor to GUI programming complexity. In order to greatly reduce programming complexity for the justnuff user base, we will need to keep the API free of programmer visible states. This means that a typical library user can simply call a GUI method to interact with the user, without having to worry about initialisation, cleanup, or dependency on any other API calls.

  4. The library should not create too many large dynamic objects.

    CPU cycles and memory resources are best spent on the application logic – the main component of jusnuff applications – instead of the GUI subsystem. In order to ensure this, the library coding must be careful not to create too many large dynamic objects during its operation – taking up valuable memory space and eventually triggering CPU intensive garbage collection.

    To satisfy this requirement, the justnuff library is specially designed and coded to re-use singleton GUI objects whenever possible.

  5. The library must be extensible.

    We only have space and time to discuss a minimal library implementation here. Users may find it necessary to customise some of the available GUI facilities for their own needs. This requirement will ensure that the user can add new functionality to the library easily.

  6. The library should be utilising some of the latest GUI features.

    Using the latest GUI facilities enables an application to appear current and relevant to the end user of the application. Judicial use of new features can also greatly simplify the design and coding of the library. A few JDK 1.4+ new GUI features really make life simpler; we will be using them in the coding of the justnuff library.

When we discuss the design and code of justnuff later, we will see how all six of these requirements are satisfied by the justnuff design.

Using the justnuff library

Using the justnuff library is very simple by design. Take a look at the JustnuffTest.java, the test program for the library. It is annotated below to show how to use the library.

You only need one single import statement for the library, highlighted below:

import uk.co.vsj.ui.justnuff.*;
import java.util.Date;
public class JustnuffTest {
Every justnuff API is a method of the UISystem class. The UISystem is a singleton (one instance only in the application), and you use the static getInstance() method to get a hold of the instance.
	private static UISystem justnuff = UISystem.getInstance();
	public JustnuffTest() {}
Our test program's logic is in the static main() method of JustnuffTest.
	public static void main(String[] args)
			throws Exception {

Status Display modal dialogs

The first call is to show an information dialog box.
justnuff.showInformationModalDialog(
"This is the justnuff UI library");
The user clicks the OK button to dismiss the dialog. The application call is blocked until the displayed GUI dialog is dismissed. Figure 3 shows the information dialog displayed.

Figure 3
Figure 3: Information dialog

The next call is to show a warning dialog box.

justnuff.showWarningModalDialog(
"Please be careful!");
The displayed warning dialog is shown in Figure 4.

Figure 4
Figure 4: Warning dialog

The next call is to show an error dialog box, and the behaviour is similar to the information and warning dialogs.

justnuff.showErrorModalDialog(
	"An internal error has occurred.");
The call to showYesNoCancelModalDialog is slightly different to the others because it returns a value indicating which button is pressed. It can be either UISystem.YES, UISystem.NO, or UISystem.CANCEL.
int tpCode = justnuff.
showYesNoCancelModalDialog(
	"Do you understand this message?");
switch (tpCode) {
	case UISystem.YES:
		justnuff.showInformationModal
Dialog("You have selected the YES option.");
		break;
		case UISystem.NO:
	justnuff.showInformationModal
Dialog("You have selected the NO option.");
		break;
	case UISystem.CANCEL:
		justnuff.showInformationModal
Dialog("You have selected the CANCEL option.");
	break;
}
Figure 5 shows the dialog that is displayed and its three buttons.

Figure 5
Figure 5: Resulting dialog

Data input dialogs

The next fragment displays a dialog requesting the user to enter a text value, in this case her/his name.
String myInput =
justnuff.showTextInputModalDialog(
	"Enter your name:");
justnuff.showInformationModalDialog(
	"You have entered a name of " + myInput );
Figure 6 shows this input dialog.

Figure 6
Figure 6: Input dialog

Once a value is entered, the showInformtionModalDialog() call is used to display the value that the application receives.

The next call, showNumericInputModalDialog, enables a user to enter a long numeric value. Unlike the text variation above, this dialog will return either a valid numeric value or 0.

long myNumber =
	justnuff.showNumericInput
ModalDialog("Enter the number of times to repeat:");
	justnuff.showInformation
ModalDialog(
	"You have requested repeat of "
	+ myNumber + " times.");
The showDateInputModalDialog() enables input of date information in a format similar to 12/1/2004. It will return either a valid Date object or null.
Date myDate =
	justnuff.showDateInputModal
Dialog("Enter the date you started work:");
justnuff.showInformationModalDialog(
	"You have entered the date " + myDate);
The showPasswordInputModalDialog() provides for input of password information. The password text is not echoed.
String myPass =
	justnuff.showPasswordInput
ModalDialog("Enter the password:");
justnuff.showInformationModalDialog(
	"You have entered the password " + myPass);
Next, the showPhoneInputModalDialog() method accepts input of a phone number in the format: (505) 555-5555. Unlike the other dialogs, this one will actually enforce the entry of the data in the required format. The return value is either a valid phone number or null.
String myPhone =
	justnuff.showPhoneInputModal
Dialog("Enter the phone number:");
justnuff.showInformationModalDialog(
	"You have entered the phone number "
	+ myPhone);
Figure 7 shows the phone dialog at work. Note the enforced data entry format.

Figure 7
Figure 7: Phine number entry dialog

The next and last method in the justnuff library is the showObjectInputModalDialog() method. This is a powerful variation of the input dialog. It can take an object as one of its arguments and then display a dialog box that enables input to each public field member of that object. The version in our sample code supports string-typed members, long-typed members, and phone-typed members. You can modify the code to handle additional type members that you may need. The sample code version also has a limit of up to 5 field members.

Object myObj = new BankAccount(0,"","","", 0);
Object myObj2 = new BankAccount2("","","",0);
Object myRet1 =
	justnuff.showObjectInputModal
Dialog("Enter values now:", myObj);
System.out.println(myRet1.toString());
myRet1=
	justnuff.showObjectInputModal
Dialog("Try values now:", myObj2);
System.out.println(myRet1.toString());
...
Figure 8 shows the first dialog that is displayed for inputting a BankAccount object.

Figure 8
Figure 8: First dialog for bank account input

The BankAccount object is defined with the following fields.

public final class BankAccount extends Object {
	public long accountNumber;
	public String firstName;
	public String lastName;
	public String phoneP;
	public long balance;
	...
Note that the phone field's name ends with a capital letter P. This is an indication to the showObjectInputModalDialog() method that this string field represents a phone number.

The final segment of code tests the showObjectInputModalDialog() method when an object either has a field type that cannot be handled, or has more than 5 field members. An error dialog is presented instead of the input dialog in this case.

Object badObj = new
	TooLargeBankAccount(
	0,"","","", 0,0);
justnuff.showObjectInputModalDialog(
	"Try values now:", badObj);
System.exit(0);
}
}
Figure 9 shows the error dialog that will be displayed.

Figure 9
Figure 9: Error dialog

You can easily test out the justnuff library by selectively commenting out different sections in the JustnuffTest.java test program and running it.

Conclusion

The justnuff library presented in this article can provide a simple-to-use GUI alternative for Java application developers who do not wish to create, maintain, and support complex and sophisticated GUI-based applications. The simplicity and extensibility of the library enable it to be adapted to a wide variety of application scenarios.


Sing Li is a consultant, trainer and freelance writer specialising in Java, web applications, distributed computing and peer-to-peer technologies. His recent publications include Early Adopter JXTA, Professional JINI and Professional Apache Tomcat, all published by Wrox Press (RIP).

You might also like...

Comments

About the author

Sing Li United States

Sing Li has been writing software, and writing about software for twenty plus years. His specialities include scalable distributed computing systems and peer-to-peer technologies. He now spends ...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.” - Rich Cook