This is the first of a series of articles on how to use the Thinlet GUI technology. The key benefit of the Thinlet framework is the power and ease it gives for developing rich user interfaces in a very small JAR file. Only 38KB for the core Thinlet JAR file will open up a new world for your applications and applets.
We'll go through each of the examples in the Thinlet distribution and explain how they operate. The examples are very good and do demonstrate the power of the framework very well.
Let us first look at the Calculator example. This displays a simple addition form that takes two numbers and adds them. Nothing at all challenging with this example but it does serve to illustrate the basic concepts without too much business logic getting in the way. Lets take a look at the main building block of any Thinlet application; the XML file that describes the user interface. If you are familiar with laying out HTML table cells then you will be at home with laying out Thinlet components. In its simplest form, one row is assumed, with all the components being laid out; left to right. One word of warning; the format of the XML file is strict; the parser is not tolerant to errors and all tags must be closed.
Below is an example XML file that lays out 5 components inside a panel. The panel has a top and left margin of 4 pixels; with each component being laid out with a padding (gap) of 4 pixels. This is our first Thinlet widget; the panel. The panel is designed to hold other components and you can think of them like an HTML table.
<panel gap="4" top="4" left="4">
<textfield name="number1" columns="4" />
<label text="+" />
<textfield name="number2" columns="4" />
<button text="=" action="calculate(number1.text, number2.text, result)" />
<textfield name="result" editable="false" />
</panel>
The next widget we see in action is the textfield widget. This field is designed to take in user input (although as we'll see you can disable this feature). We assign a unique name to the textfield so we can later refer to it. The columns attribute defines the width of the field; this is the number of characters wide we'll make the field.
The next widget is the label widget which is used to display text. As we'll see in later tutorials you can use label to display images as well as text. This is a very useful widget. The value it displays is given using the text attribute.
Finally we have the button widget which displays a button on the form. Now notice the action attribute. This is the method that is called when this button is pressed. This is where the power of Thinlets start to show. Thinlets uses reflection to find the right method to call. The class that utilise's this XML file must have a method defined with the signature:
public void calculate(String text1, String text2, Object widget )
The return method doesn't matter, but the method signature must match what is defined in the XML file. In the XML file we've defined that when this method is called, we'll be using the text value from the first textfield as the first parameter, the second text value from the second textfield, passing in the name of the resulting field we wish to use to display the value.
Let's take a look at the Java code that utilise's this XML file. The first thing you will notice is the main() method that is used to kick start the application. The thinlet.FrameLauncher class is used to create the necessary wrapper to allow the thinlet application to be created.
package thinlet.demo;
import thinlet.*;
public class Calculator extends Thinlet {
public Calculator() throws Exception {
add(parse("calculator.xml"));
}
public void calculate(String number1, String number2, Object result) {
try {
int i1 = Integer.parseInt(number1);
int i2 = Integer.parseInt(number2);
setString(result, "text", String.valueOf(i1 + i2));
} catch (NumberFormatException nfe) {
getToolkit().beep();
}
}
public static void main(String[] args) throws Exception {
new FrameLauncher("Calculator", new Calculator(), 320, 240);
}
}
The class is based on the thinlet.Thinlet class which has lots of methods to help you poke around the various widgets in the framework. These will be exposed over the due course of these tutorials.
thinlet.Thinlet is itself based on the java.awt.Container class. The parse("calculator.xml") method will load the XML file, parse it and create a component to add to the main root component using the add(..) method. Once this call completes the GUI will be visible and ready to use; nothing more to it than that.
As you've noticed the calculate(..) method we described in the XML is defined. The main purpose of this method is to add two numbers together and set the result widget with the value. We do this using the 'setString(..)' method.
One of the biggest stumbling blocks with using thinlets is its lack of strongly typed classes; everything is just an Object. This is mainly for performance and to keep the overall size of the library to a minimum. For a language that is strongly typed this can be quite strange to get use to. With that in mind, you don't call methods on the object instead you use the object as a reference to which to make calls.
In this example we use the setString(..) method, passing in the action object we want to operate on. Which here, is the 'result' widget we identified in the XML file. We want to set the 'text' property widget with our new value. Thats it. Once we make the call to setString(..) we don't need to make any refresh calls to the UI; its all done under the covers for us. Easy eh?
But lets modify things a little to show you the opposite of the setString(..). In the XML file lets say on the button press we simply use action="calculator()". This would render our new calculate method shown below:
public void calculate(){
try{
Object field1 = find("number1");
Object field2 = find("number2");
Object result = find("result");
int i1 = Integer.parseInt( getString(field1,"text") );
int i2 = Integer.parseInt( getString(field2,"text") );
setString(result, "text", String.valueOf(i1 + i2));
} catch (NumberFormatException nfe) {
getToolkit().beep();
}
}
As can be seen, instead of the values being passed into us, we find them based on their logical name we gave them in the XML file. This is done using the find(..) method which returns the Object representing the textfield. Then, using the getString(..) method, passing in the object we wish to operate with coupled with the property we wish to find.
Which method you use to work with your API depends largely on your application, but both exist to give you the choice. But the key thing to remember is that Objects are not there to be operated on, but to be operated with. This is the fundamental building block of Thinlet UI's.
We'll look at the other examples that expose more of the Thinlet API in later tutorials.