blog community
JavaFX 1.2 example: Folder Visualizer

Last year I blogged about a small JavaFX project I implemented called Folder-Visualizer. The tool lets you find large files and directories to effectively clean your hard disk. The previous version of the tool was implemented with an early beta of JavaFX. I reimplemented it with JavaFX 1.2, now using standard components, charts and background tasks. I will show some of the code to give an idea what it takes to implement a real application with the current version of JavaFX.

 

Charts

In a previous post I blogged about the new charting components in JavaFX 1.2. They are easy to use. Common functionality such as rendering from a sequence of data and clicking on a part of the chart is all supported, and they look ok too. In the PieChart there is a very annoying rendering error however (the black line at the left top) which is always there. And while I think the charts look good, they are nowhere near the looks of the Flex charting components yet...

 

Temporarily adding nodes

Sometimes you want to add a node temporarily. For example, when this app is indexing, the chart is removed and a ProgressIndicator is displayed. As soon as the indexing process is finished, the ProgessIndicator is removed again and the new chart is added to the scene. The easiest way to remove a node is by using it's id. You can give a node an id by setting the id property, which is a String. Next you can use the "lookup" function on Scene. This is very  much like the "getElementById" method in JavaScript, and you can use it the same way. So to remove the chart (id: "chart") you can use the following code:

delete scene.lookup("chart")  from scene.content;

Also remember that the scene's content is just a sequence. This means you can easily add nodes on the fly too, for example:

  insert ProgressIndicator {
             id: "progress"
             progress: -1;
             translateX: 300
             translateY: 400
             scaleX: 10
             scaleY: 10
           } into scene.content;    

 

Binding to Java

The actual scanning and indexing of directories is implemented in Groovy. The Groovy classes are simply packaged in a JAR file, and the JAR file is used from JavaFX. JavaFX can call any Groovy code without a problem, but some extra work was still necessary. The Groovy classes return a java.util.List with the indexing information. JavaFX can use lists, but you can't use binding on it. The following code for example will not compile:

 var list = new ArrayList();
    list.add("Str1");
    list.add("Str2");

    var seq = bind for(item in list) {
        item;
    }

This can be partly solved by transforming the List into a Sequence yourself (example below) so you can at least use binding and sequence syntax in the rest of the code, but you still need to update the sequence yourself when the List is changed. 

function createSequence(list : List) : FolderItem[]{
    var items : FolderItem[] = [];

    for(item in list) {
        insert item as FolderItem into items;
    };

    return items;
}

While this might look like a problem, it's just a inconvenience. It's great that JavaFX call Java. This feature alone makes JavaFX more interesting than AIR, where your whole app must be ActionScript. While I don't mind writing the UI in a new (less mature) language, I don't want to write all my code in it. 

 

Strange binding bug?

I did run into some strange error at some point. As you might have noticed in the code of the BreadCrum, I use a bind for color while this is already in a bound context. To me this seems unnecessary. However if I remove the bind, the application still works correctly, but also shows a warning at the command line, telling that a node was added to a Group while not removed from it's old Group. I can't explain it at this moment, and to me it seems like a bug. 

Talking about bugs, I found that a lot of bugs are fixed in version 1.2. In previous versions I did still sometimes run into, often binding related, bugs. Besides this error everything worked exactly as expected. 

 

Using FileChooser

JavaFX doesn't have a FileChooser component. You can use the Swing JFileChooser without any problem however, and it doesn't compromise rendering since a native window is used anyway. 

var fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

var retVal = fc.showOpenDialog(null);

if(retVal == JFileChooser.APPROVE_OPTION) {
   dirNameInput.text = fc.getSelectedFile().getAbsolutePath();
}

 

Executing background tasks

Another new feature in JavaFX 1.2 is support for background task execution. In the Folder-Visualizer application the indexing can potentially take a long time, and you don't want the interface to freeze as soon as indexing starts. The indexing should run in a separate thread obviously. JavaFX has the JavaTaskBase class that is similar with Java's Callable. You need to override the "create" function that returns a RunnableFeature. The RunnableFeature contains the real work, and can be implemented in Java. When the task is done, you probably want to change something in the UI. Similar to Swing programming you can use a method "Entry.deferAction(Runnable)" to run code on the UI thread. The code that will run on the UI thread is a callback.

Confused yet? It took me a minute to grasp it. Three extra classes to just execute a piece of Java code on the background. While it's an elegant solution, it's still feels like a lot of work. So to summarize you'll need the following

 

  1. A task description (written in JavaFX, extends JavaTaskBase)
  2. A RunnableFuture implementation (written in Java, implements RunnableFuture)
  3. A callback interface (so that Java can call JavaFX)

 

I will show the implementation of each class, and the code that actually starts the task.

Task Description

public class VisualizeTask extends JavaTaskBase{
    public var dir : String;
    public var callback : FXListener;

    public override function create() {
       new VisualizeFuture(dir, callback);

    }

}

 

RunnableFuture implementation

public class VisualizeFuture implements RunnableFuture {

    private final FXListener listener;
    private final String dir;
    

    public VisualizeFuture(final String dir, final FXListener listener) {
        this.listener = listener;
        this.dir = dir;       
    }

    public void run() throws Exception {
        Folder folder = new Folder(dir);
        FolderVisualizer visualizer = FolderVisualizer.create(folder);
        final List<FolderItem> items = visualizer.toVisualize(folder, 5);

        Entry.deferAction(new Runnable() {

            public void run() {
                listener.callback(items);
            }
        });
    }
}

 

Callback interface

public interface FXListener {
    public void callback(List<FolderItem> items);
}

 

Executing the task

 var visualizeTask = VisualizeTask {
        dir: dirNameInput.text
        callback: FXListener {
            override function callback(ret : List) : Void{                
                createChart(createSequence(ret));
            }
        }
    };

 

Downloading Folder-Visualizer and check the code

The Folder-Visualizer is hosted at Google Code: http://folder-visualizer.googlecode.com. You can install the application by simply clicking the JNLP file, it will install as Webstart application. Besides the JavaFX version, there is a AIR version developed by Jamie Craane

 


Posted 17-08-2009 16:22 by Paulb
Filed under:

Add a Comment

(required)  
(optional)
(required)  
Remember Me?
Enter code (required)
Powered by Community Server (Commercial Edition), by Telligent Systems