Thinlets can be used to create very powerful user interfaces at runtime as oppose to precanned solutions. This tutorial will look at how you can dynamically add new tabs to the TabbedPane control at run time.
Let us look at how you would put together a simple text editor program that would open up a new tab for each file you wanted to edit. For each file, we'll display the full path of the file and the contents of a file in a text area. We won't go into too much detail with this, except for the user interface.
The first thing we'll do is to give our application a very simple interface, with a menu bar along the top and a 'tabbedpane' holder in the main body of the window. We'll name the tabbedpane widget 'tabparent' which will allow us to easily get a handle to it.
<panel columns="1" gap="4">
<menubar weightx="1">
<menu text="File">
<menuitem text="Open" action="menuOpen"/>
<menuitem text="Save" action="menuSave""/>
<menuitem text="Exit" action="menuExit""/>
</menu>
</menubar>
<tabbedpane name="tabparent" placement="top" weighty="1">
</tabbedpane>
</panel>
The tabbedpane widget is very flexible giving you the ability to place the tabs on any side of the control, including the ability to stack them vertically as oppose to horizontally. We have defined the weighty='1' here, which indicates that we want the control to take up all the available vertical space. The only widget permitted inside a tabbedpane widget is the 'tab' widget. We will add these dynamically.
The java code for breathing life into this Thinlet XUL file is shown next.
import thinlet.*;
public class tabExample extends Thinlet {
public static void main(String[] args) throws Exception {
new FrameLauncher("Tab Example", new tabExample(), 500, 440);
}
public tabExample() throws Exception {
add( parse("tabExample.xml") );
}
//- action handlers for the menu items
public void menuOpen(){}
public void menuSave(){}
public void menuExit(){}
}
What we'll do now is to develop a method for tabExample.java that when triggered, will add a new tab to the tabbedpane. We could trigger this method for each file we load, or on response to the the menu 'Open' being made. Doesn't really matter how its triggered for the sake of this example, just important to know how it works.
We can prebuild a series of tab panels and save them in a series of XML files. For example we could develop different ones for different file types. Lets look at a simple one for text files.
<tab text="">
<panel weighty="1" weightx="1" columns="1" gap="4">
<panel columns="2" weighty="0" weightx="0" top="4" gap="4">
<label text="Filename: "/>
<textfield text="" weightx="1" />
</panel>
<textarea text="TextArea" wrap="true" weightx="1" weighty="1"/>
<panel gap="4" halign="right">
<button text="save" alignment="left"/>
<button text="close" alignment="left"/>
</panel>
</panel>
</tab>
When dealing with 'tab' widgets, you are only permitted one widget inside of them. In this example we first furnish the tab area with a panel widget and then lay out all our widgets inside of that panel. As you can see, it will display a top line of a label with a textfield. In the main body, the textarea will consume most of the window space, with finally, two buttons laid out at the bottom, aligned to the right of the tab. We'll save this in a file called; 'texttab.xml'.
On a given action we want to take this XML file, load and parse it, and finally place it inside the main tabbedpane widget. The following method will do just that.
public void addTextTab(){
try{
Object newTab = parse("texttab.xml");
Object tabParent = find("tabparent");
if ( tabParent != null ){
setString( newTab, "text", "Text File" );
add( tabParent, newTab );
}
}catch(Exception E){
E.printStackTrace();
}
}
The first thing we do is to parse the texttab.xml file by simply calling parse(..) from the Thinlet framework. This will create the necessary components from the XML file and return back an object handle for us to work with it. Next we find the tabbedpane widget we wish to insert this newly created tab into by using the find(..) method. Assuming the widget was found (find will return null if not), we'll first set the name of the tab to 'Text File' and then add it to the tabbedpane using the Thinlet method add(..).
It is that simple.
The new tab will be inserted into the main tab and be ready to use without any further calls to update the UI or refresh the screen. This powerful feature allows you to build up sections of the GUI as and when they are needed as oppose to building them all and then hiding them until they are required.