How to use WebAsyncTree?

Some of frequently asked questions are saved here.
You might find some answers for your questions in this forum.

How to use WebAsyncTree?

Postby mgarin » Wed Apr 24, 2013 3:06 pm

What is it?

Asynchronous tree is a small JTree (WebTree) extension that allows you to load tree data asynchronously (in a separate thread) without blocking the UI updates. This tree is very useful for some cases when you cannot load tree data fast or data loading methods could handle for a while.

For example WebFileTree is now based on WebAsyncTree and doesn't block the UI if file system doesn't respond fast enough. It simply displays a loader icon on the tree node while childs are being loaded.

What should i know about it?

WebAsyncTree uses specific nodes and model that is why you should know how to use them properly.

AsyncUniqueNode

WebAsyncTree can work only with AsyncUniqueNode, that is why you should provide this node type (or any node that extends AsyncUniqueNode) when working with this tree. Each node of this type has an unique ID, busy state variable and special loader icon that supports animation.

Busy state is updated by the tree itself. Loader icon can be used within your own renderer to display busy state (if you want to display it of course).

AsyncTreeDataProvider

This is the heart of the WebAsyncTree - this interface provide basic methods which you should implement to allow the tree to retrieve its root and lazy-load node childs.

List of available methods (E extends AsyncUniqueNode):

public E getRoot ();
Returns asynchronous tree root node.
This request uses the EDT and should be processed quickly.

public List<E> getChilds ( E node );
Returns child nodes for specified asynchronous tree node.
This request uses a separate thread and might take a lot of time to process.

public boolean isLeaf ( E node );
Returns whether the specified node is leaf (doesn't have any childs) or not.
This request uses the EDT and should be processed quickly.
If you cannot be sure if the node is leaf or not - simply return false - this will allow the tree to expand this node on request. It is not recommended to perform any reqests that could handle for a while here as it will handle the UI aswell.

Basically - these three methods are sufficient to provide tree with data.

You can see this interface implementation examples here:
https://code.google.com/p/weblookandfee ... vider.java
https://code.google.com/p/weblookandfee ... eTree.java (FileTreeDataProvider inner class)

How to use WebAsyncTree?

You already know the basics required to use WebAsyncTree, let's try it out!
And don't panic! There is a lot of comments in the code below, but the code itself is really small.

First of all, let's make a custom node for your new tree:
Code: Select all
import com.alee.extended.tree.AsyncUniqueNode;

/**
 * Sample node.
 *
 * @author Mikle Garin
 * @since 1.4
 */

public class SampleNode extends AsyncUniqueNode
{
    /**
     * Node name to display.
     */
    private String name;

    /**
     * Node type.
     */
    private SampleNodeType type;

    /**
     * Constructs sample node.
     *
     * @param name node name
     * @param type node type
     */
    public SampleNode ( String name, SampleNodeType type )
    {
        super ();
        this.name = name;
        this.type = type;
    }

    /**
     * Returns node name.
     *
     * @return node name
     */
    public String getName ()
    {
        return name;
    }

    /**
     * Changes node name.
     *
     * @param name new node name
     */
    public void setName ( String name )
    {
        this.name = name;
    }

    /**
     * Returns node type.
     *
     * @return node type
     */
    public SampleNodeType getType ()
    {
        return type;
    }

    /**
     * Changes node type.
     *
     * @param type new node type
     */
    public void setType ( SampleNodeType type )
    {
        this.type = type;
    }
}
Code: Select all
/**
 * Sample node types enumeration.
 *
 * @author Mikle Garin
 * @since 1.4
 */

public enum SampleNodeType
{
    /**
     * Root element type.
     */
    root,

    /**
     * Folder element type.
     */
    folder,

    /**
     * Leaf element type.
     */
    leaf
}


Now create an AsyncTreeDataProvider for your tree:
Code: Select all
import com.alee.extended.tree.AsyncTreeDataProvider;
import com.alee.utils.CollectionUtils;
import com.alee.utils.ThreadUtils;

import java.util.List;

/**
 * Sample asynchronous tree data provider.
 *
 * @author Mikle Garin
 * @since 1.4
 */

public class SampleDataProvider implements AsyncTreeDataProvider<SampleNode>
{
    /**
     * Returns asynchronous tree sample root node.
     *
     * @return root node
     */
    public SampleNode getRoot ()
    {
        // Custom root node
        return new SampleNode ( "Root", SampleNodeType.root );
    }

    /**
     * Returns smaple child nodes for specified asynchronous tree node.
     *
     * @param parent childs parent node
     * @return list of child nodes
     */
    public List<SampleNode> getChilds ( SampleNode parent )
    {
        // Sample loading delay to see the loader in progress
        ThreadUtils.sleepSafely ( 1000 );

        // Sample childs
        switch ( parent.getType () )
        {
            case root:
            {
                // Folder type childs
                final SampleNode folder1 = new SampleNode ( "Folder 1", SampleNodeType.folder );
                final SampleNode folder2 = new SampleNode ( "Folder 2", SampleNodeType.folder );
                final SampleNode folder3 = new SampleNode ( "Folder 3", SampleNodeType.folder );
                return CollectionUtils.asList ( folder1, folder2, folder3 );
            }
            case folder:
            {
                // Leaf type childs
                final SampleNode leaf1 = new SampleNode ( "Leaf 1", SampleNodeType.leaf );
                final SampleNode leaf2 = new SampleNode ( "Leaf 2", SampleNodeType.leaf );
                final SampleNode leaf3 = new SampleNode ( "Leaf 3", SampleNodeType.leaf );
                return CollectionUtils.asList ( leaf1, leaf2, leaf3 );
            }
        }

        // You can return either null or empty list if there are no childs
        return null;
    }

    /**
     * Returns whether the specified sample node is leaf or not.
     *
     * @param node node
     * @return true if the specified node is leaf, false otherwise
     */
    public boolean isLeaf ( SampleNode node )
    {
        // Simply check the node type to determine if it is leaf or not
        return node.getType ().equals ( SampleNodeType.leaf );
    }
}


I did not mention t before, but you might need to change tree cell renderer and editor to fit your data. There is nothing special about it, simply extend WebTreeCellRenderer and WebTreeCellEditor and change whatever you need to. Just don't forget to use the custom loader icon from the AsyncUniqueNode in the renderer if you want the tree to display nodes busy state:
Code: Select all
import com.alee.laf.tree.WebTreeCellRenderer;
import com.alee.laf.tree.WebTreeElement;
import com.alee.laf.tree.WebTreeUI;

import javax.swing.*;

/**
 * Sample asynchronous tree cell renderer.
 *
 * @author Mikle Garin
 * @since 1.4
 */

public class SampleTreeCellRenderer extends WebTreeCellRenderer
{
    /**
     * Returns custom tree cell renderer component
     *
     * @param tree       tree
     * @param value      cell value
     * @param isSelected whether cell is selected or not
     * @param expanded   whether cell is expanded or not
     * @param leaf       whether cell is leaf or not
     * @param row        cell row number
     * @param hasFocus   whether cell has focusor not
     * @return renderer component
     */
    public WebTreeElement getTreeCellRendererComponent ( JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf,
                                                         int row, boolean hasFocus )
    {
        super.getTreeCellRendererComponent ( tree, value, isSelected, expanded, leaf, row, hasFocus );

        // Node icon
        final SampleNode node = ( SampleNode ) value;
        if ( node.isBusy () )
        {
            // Loader icon
            setIcon ( node.getLoaderIcon () );
        }
        else
        {
            // Type icon
            switch ( node.getType () )
            {
                case root:
                {
                    setIcon ( WebTreeUI.ROOT_ICON );
                    break;
                }
                case folder:
                {
                    setIcon ( expanded ? WebTreeUI.OPEN_ICON : WebTreeUI.CLOSED_ICON );
                    break;
                }
                case leaf:
                {
                    setIcon ( WebTreeUI.LEAF_ICON );
                    break;
                }
            }
        }
       
        // Node text
        setText ( node.getName () );

        return this;
    }
}
Code: Select all
import com.alee.laf.text.WebTextField;
import com.alee.laf.tree.WebTreeCellEditor;

import javax.swing.*;
import java.awt.*;

/**
 * Sample tree cell editor.
 *
 * @author Mikle Garin
 * @since 1.4
 */

public class SampleTreeCellEditor extends WebTreeCellEditor
{
    /**
     * Last edited node.
     */
    private SampleNode sampleNode;

    /**
     * Constructs sample tree cell editor.
     */
    public SampleTreeCellEditor ()
    {
        super ();
    }

    /**
     * Returns custom tree cell editor component.
     *
     * @param tree       tree
     * @param value      cell value
     * @param isSelected whether cell is selected or not
     * @param expanded   whether cell is expanded or not
     * @param leaf       whether cell is leaf or not
     * @param row        cell row index
     * @return cell editor component
     */
    public Component getTreeCellEditorComponent ( JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row )
    {
        this.sampleNode = ( SampleNode ) value;
        WebTextField editor = ( WebTextField ) super.getTreeCellEditorComponent ( tree, value, isSelected, expanded, leaf, row );
        editor.setText ( sampleNode.getName () );
        return editor;
    }

    /**
     * Returns current editor's value.
     *
     * @return current editor's value
     */
    public Object getCellEditorValue ()
    {
        sampleNode.setName ( super.getCellEditorValue ().toString () );
        return sampleNode.getName ();
    }
}


Now you can create a working asynchronous tree:
Code: Select all
import com.alee.extended.tree.WebAsyncTree;
import com.alee.extended.tree.sample.SampleDataProvider;
import com.alee.extended.tree.sample.SampleNode;
import com.alee.extended.tree.sample.SampleTreeCellEditor;
import com.alee.extended.tree.sample.SampleTreeCellRenderer;
import com.alee.extended.window.TestFrame;
import com.alee.laf.scroll.WebScrollPane;

/**
 * @author Mikle Garin
 * @since 1.4
 */

public class AsyncTreeExample
{
    public static void main ( String[] args )
    {
        // Create data provider
        SampleDataProvider dataProvider = new SampleDataProvider ();

        // Create a tree based on your data provider
        WebAsyncTree<SampleNode> asyncTree = new WebAsyncTree<SampleNode> ( dataProvider );
        asyncTree.setVisibleRowCount ( 8 );
        asyncTree.setEditable ( true );

        // Setup cell renderer and editor
        asyncTree.setCellRenderer ( new SampleTreeCellRenderer () );
        asyncTree.setCellEditor ( new SampleTreeCellEditor () );

        // Show an example frame
        new TestFrame ( new WebScrollPane ( asyncTree, false ) );
    }
}


hostingkartinok_com_8367068778661089971.png
WebAsyncTree
hostingkartinok_com_8367068778661089971.png (3.87 KiB) Viewed 2970 times

hostingkartinok_com_8807203092193801158.png
WebAsyncTree
hostingkartinok_com_8807203092193801158.png (3.88 KiB) Viewed 2970 times


Clean and easy, isn't it? :)

P.S. This example could be also found in library - this is actually the default WebAsyncTree data.
User avatar
mgarin
Site Admin
 
Posts: 223
Joined: Mon Apr 16, 2012 1:01 pm
Location: Russia, Saint-Petersburg

Return to FAQ

Who is online

Users browsing this forum: No registered users and 1 guest

cron