Customizing uitree

Last week, I introduced the semi-documented uitree function that enables displaying data in a hierarchical (tree) control in Matlab GUI.

Today, I will continue by describing how uitrees can be customized.

Note that although uitrees use Java objects internally, we can create and customize uitree using pure-Matlab code.

Creating non-standard tree types

To start the discussion, let’s create a simple uitree whose Root node is not one of the automatically-processed types (disk folder, GUI handle, or Simulink model). There are two ways of creating such a tree: active and reactive:

Actively building the tree

In this method, we actively create nodes and attach them to parent nodes when the tree is first built. For example:

% Fruits
fruits = uitreenode('v0', 'Fruits', 'Fruits', [], false);
fruits.add(uitreenode('v0', 'Apple',  'Apple',  [], true));
fruits.add(uitreenode('v0', 'Pear',   'Pear',   [], true));
fruits.add(uitreenode('v0', 'Banana', 'Banana', [], true));
fruits.add(uitreenode('v0', 'Orange', 'Orange', [], true));
 
% Vegetables
veggies = uitreenode('v0', 'Veggies', 'Vegetables', [], false);
veggies.add(uitreenode('v0', 'Potato', 'Potato', [], true));
veggies.add(uitreenode('v0', 'Tomato', 'Tomato', [], true));
veggies.add(uitreenode('v0', 'Carrot', 'Carrot', [], true));
 
% Root node
root = uitreenode('v0', 'Food', 'Food', [], false);
root.add(veggies);
root.add(fruits);
 
% Tree
figure('pos',[300,300,150,150]);
mtree = uitree('v0', 'Root', root);

The tree automatically display scrollbars if any of the presented tree-nodes requires more than the available tree space:

User-created tree    User-created tree

User-created tree

Reactively building the tree

In this method, also called “lazy loading”, we only create child nodes as a reaction to their parent node’s expansion. This is the method given in uitree‘s semi-documented help section. The tree will initially display only the root node, and additional tree-nodes will be created as needed when the root or any of its child nodes is expanded.

For example (note how the data model is passed as an extra parameter to the ExpandFcn callback):

% Create the data
food.veggies = {'Potato','Tomato','Carrot'};
food.fruits = {'Apple','Pear','Banana','Orange'};
 
% Create the tree with an ExpandFcn  callback
root = uitreenode('v0', 'Food', 'Food', [], false);
figure('pos',[300,300,150,150]);
mtree = uitree('v0', 'Root',root, 'ExpandFcn',{@myExpandFcn,food});
 
% The following function should be added to Matlab's path:
function nodes = myExpandfcn(tree, value, model)
  try
    nodeIdx = 0;
    if strcmp(value,'Food')
      nodeNames = fieldnames(model);
      isLeaf = false;
    else
      nodeNames = model.(value);
      isLeaf = false;
    end
    for nodeIdx = 1 : length(nodeNames)
      nodeName = nodeNames{nodeIdx};
      nodes(nodeIdx) = uitreenode(nodeName,nodeName,[],isLeaf);
    end
  catch
    % never mind...
  end
  if isempty(nodeIdx) || nodeIdx == 0
      nodes = [];
  end
end

Resizing the tree

uitrees are created with a default position of (0,0), a width of 200 (or less if the figure is narrower) and a height spanning the entire figure’s content area. This can easily be modified following the tree’s creation using its Position property:

mtree = uitree(...);
mtree.Position = [100,100,50,150];  % modify position & size
mtree.Position(4) = 100;  % limit tree height to 100 pixels

Java-based customizations

Today’s article used pure Matlab code (or more precisely, Java code wrapped in pure Matlab). Many additional customizations are available at the JTree-level. The underlying jtree handle can easily be retrieved:

jtree = mtree.getTree;
jtree = get(mtree, 'tree');  % an alternative

As an example customization that uses jtree, consider one of my earliest articles on this website: Adding a context-menu to a uitree.

Interested readers might also benefit from looking at the tree manipulations that I have programmed in my FindJObj utility.

Next week’s article will conclude my uitree mini-series by describing how specific tree nodes can be customized. If you have any special customization request, please post a comment below.

Categories: GUI, Java, Medium risk of breaking in future versions, Semi-documented function

Tags: , , , ,

Bookmark and SharePrint Print

43 Responses to Customizing uitree

  1. Scott Koch says:

    Hi Yair –

    Thanks for your uitree series. As far as customization goes I’d be interested in creating components for nodes (button, combo box, and maybe even a editable text field).

    Scott

  2. Jason says:

    Hi Yair,

    Since your very first posts I began to experiment with uitree, I think you convinced me that MATLAB isn’t as locked-down as I thought…

    Anyway, regarding uitree customizations, it would be interesting to see how to manage the drag behavior outside the uitree panel. Let’s say we don’t care about drop position, but we want to drag a file tree selection (for example) to another panel. The effect might be to import data files into a plot or something like that.

    Regards,
    Jason

    • @Scott – I have an entire article planned to answer your question, showing how this can be done in several different ways. Hold on…

      @Jason – DnD is a complex issue that requires a mini-series of its own. It’s in my TODO list, but not planned for the near future…

  3. Prasath says:

    Yair,

    Is there a way in MATLAB to differentiate tree nodes in unique colors ?. I mean first node in red, second in blue, third in green and so on.

    Thanks,
    Prasath
    =========

  4. Pingback: Customizing uitree nodes – part 2 | Undocumented Matlab

  5. Chris says:

    Hello Yair,

    thank you very much for your numerous explanations around the uitree functionality in Matlab. Without this I had never managed to make a GUI with working tree menu.

    But I have still one open question: Is it possible to get and set the expansion structure of the tree menu? If a add menu items on the fly by user input and reload the tree menu, all nodes are collapsed. I am searching for a way to expand – after a reload – exactly the items which were expanded before.

    Do you know a method to realize this?

    Thank you in advance.

    Regards
    Chris

    • @Chris – collapsing/expansion are tree capabilities, not node capabilities. After all, hierarchy nodes can be presented in several different formats (other than a tree) that do not necessarily involve collapsing/expansion.

      The tree object (jtree = mtree.getTree) has the isCollapsed(nodeNumber) / isExpanded(nodeNumber)methods that you can use to query the state, and corresponding collapseRow(nodeNumber) / expandRow(nodeNumber) methods for setting the state. There are also similar methods for querying/setting the state of a given hierarchy path.

      Read here for more details.

      -Yair

  6. rahill says:

    Hi Yair
    I ready need to know about drag and drop in matlab uitree,I have a treeview with 2 chil node in level 1.one of them will show data file names,and the second have some nodes that will define plot types, I want to drag the data name and drop it to plot types,I really need to know more about it.
    Could you help me please?
    thanks for your attention.
    rahill

    • @Rahill – yes this is possible, but it is not easy. It is certainly not something that I can explain in a blog comment. I plan to write about DND in a series of articles sometime in early 2012. In the meantime, if you would like my consulting assistance, please contact me by email (use the link at the top right of any page on the website).

  7. Jason D. says:

    I’m using a tree control and a list box in conjunction with each other. Between the two are left/right arrow buttons, so items from the tree may be move to the list and vice versa. I’ve been trying to find some easy mechanism to track items to hide/show or add/remove, such as keeping track of which items in the tree control have been selected for the list box and then forcing node expansion to refresh the children shown. The expand callback doesn’t seem to be triggering beyond the first expansion done.

    What I’m currently doing is removing all nodes with a particular parent (category, basically) and then reloading the children from the data model. I tried doing a sort of insert to just put the item back roughly where it was removed, but I can’t seem to find the proper syntax to insert a node at a particular position in the list of children.

    So, is there a way to force the expand callback function to refresh the child nodes? Is there an efficient way to insert a child at a particular position?

    Thanks.

  8. ninad says:

    Hi,Great work.
    How to use the swingx treetable in matlab.

    • @Ninad – this is outside the scope of a simple blog comment. In general, you need to get your relevant Java classes (table model, cell renderers/editors) into the Java classpath, then instantiate the JXTreeTable object in Matlab and call its various methods to configure it, and finally display it onscreen using the javacomponent function. There are several online resources with examples showing how to create the Java classes (example).

      As an alternative to JXTreeTable, consider using JIDE’s TreeTable, which is already included in Matlab.

      If you need personal assistance with setting any of these, please email me for a consulting proposal.

  9. Graham Searle says:

    I’m trying to integrate a uitree into a GUI with a black background. I can set the tree’s background color as required, but it doesn’t quite achieve what I hoped – the names of each node retain a white border.
    Here’s an example code snippet:

    myFig = figure;
    rootNodeDesc = 'myTree';
    root = uitreenode('v0','somethingOrOther',rootNodeDesc,[],false);
    nodeDesc = 'myNode';
    node = uitreenode('v0','val',nodeDesc,[],true);
    root.add(node)
    mtree = uitree('v0','Root',root,'parent',myFig);
    jtree = mtree.getTree;
    jtree.setBackground(java.awt.Color(0,0,0));

    Anyone have any suggestions please?
    See the screenshot in the following link if you want to see what I see (using R2008b and R2012a) – click for hi-res image:

    Thanks!

  10. yh says:

    I tried this example, but I can only see the root(Food). what is the problem?
    Thanks

  11. Simon says:

    Hi Yair,

    As far as I understand, each uitree comes with its own panel. Is it possible two uitree’s to share a common panel? Fir example, add ‘Drinks’ to the same level as ‘Food’?

    Thanks

    • @Simon – you can make both Food and Drinks children of the same uitree root. You can then decide whether or not to display the root:

      jtree.setRootVisible(false);

      There is also a corresponding ShowsRootHandles property. This is all explained in p. 179 of my book.

  12. Pezz says:

    Hello, how to i add another level of nodes, so for example add below Apple, ‘Granny Smith’,’Sweet’,’Cooking’ etc?

  13. Ben Lawrence says:

    Is there a way of displaying the ‘value’ of leaf (a vector, a scalar, a string, etc) to the right of the ‘name’ of the leaf in the uitree gui?

    • Yair Altman says:

      @Ben – simply update the lean name (label) to include all the information that you need. You can use HTML formatting if you wish.

    • Ben says:

      Thanks – Do you mean just put all the info as a string into the ‘name’ field? If I used HTML formatting will that allow me to format the ‘name’ and the ‘value’ data differently? are there any examples out there?

    • Yair Altman says:

      @Ben – yes. You will need to learn HTML, it’s not too difficult. Example: ‘<html><b>Name</b>: <i>Value’

  14. kpmandani says:

    In the above figure example,can we get a check box against potato,tomato, carrot for vegetables and apples,pear, banana… in fruits? If so can anyone suggest me what code should I add to the above existing code to get it?

  15. kpmandani says:

    What I am trying is similar to what we see in computers. Eg when we go inside a folder and select a file, the line below the menu bar shows the file/folder location. Can I do it the same for the above and display its output in the command window?

  16. Sebastian says:

    Hi Yair,

    I am using the uitree inside a MATLAB GUI. Basically I want to browse in .mat-files (simulation results). Until now I am able generate a uitree, but I am not able to delete it and load another .mat-file. Can you help me how it is possible to use uitrees for different .mat-files?

    Thank you very much,
    Sebastian

    My code example for the generation of a uitree:

    import javax.swing.*;
    warning('off', 'MATLAB:hg:JavaSetHGProperty');
     
    [filename,pathname]=uigetfile('*.mat', 'File zum Laden auswählen');
    a=[pathname,filename];
    data = load(a);
    name = fieldnames(data);
     
    handles.data = cell(2,1);
    handles.data{1} = data;
     
    handles.root = uitreenode('v0', filename, filename, [], false);
    handles.tree = uitree('v0', hObject,'Root', handles.root,'ExpandFcn', @(obj, ev)myExpfcn4(obj, ev, hObject, handles));
    set(handles.tree, 'Units', 'normalized', 'position', [0 0 0.25 1]);
    set(handles.tree, 'NodeWillExpandCallback', @(obj, ev) nodeWillExpand_cb4(obj, ev, hObject, handles));
    set(handles.tree, 'NodeSelectedCallback', @(obj, ev)nodeSelected_cb4(obj, ev, hObject, handles));
     
    handles.t = handles.tree.Tree;
    set(handles.t, 'MousePressedCallback', @mouse_cb);
     
    warning('on', 'MATLAB:hg:JavaSetHGProperty');
    • @Sebastian – did you try to simple create a new uitreenode for the new file and then set the tree’s Root property to this new node?

    • Sebastian says:

      @Yair: Thank you very much for your answer!
      In my MATLAB-GUI I have a pushbutton for opening a new file. In the Callback of this pushbutton I am using the following code:

      % --- Executes on button press in open_pb.
      function open_pb_Callback(hObject, eventdata, handles)
      % hObject    handle to open_pb (see GCBO)
      % eventdata  reserved - to be defined in a future version of MATLAB
      % handles    structure with handles and user data (see GUIDATA)
      [filename,pathname]=uigetfile('*.mat', 'File zum Laden auswählen');
      a=[pathname,filename];
      data = load(a);
      name = fieldnames(data);
       
      handles.data = cell(2,1);
      handles.data{1} = data;
       
      handles.root = uitreenode('v0', filename, filename, [], false);
      handles.tree = uitree('v0', hObject,'Root', handles.root,'ExpandFcn', @(obj, ev)myExpfcn4(obj, ev, hObject, handles));
       
      % Update handles structure
      guidata(hObject, handles);

      When I execute this pushbutton, I get the following error message:

      Error using uitree_deprecated
      Unrecognized parameter.
       
      Error in uitree (line 102)
      	[tree, container] = uitree_deprecated(varargin{2:end});
       
      Error in tree_inspector>open_pb_Callback (line 385)
      handles.tree = uitree('v0', hObject,'Root', handles.abc,'ExpandFcn', @(obj,ev)myExpfcn4(obj, ev, hObject, handles));
       
      Error in gui_mainfcn (line 95)
              feval(varargin{:});
       
      Error in tree_inspector (line 42)
          gui_mainfcn(gui_State, varargin{:});
       
      Error in
      matlab.graphics.internal.figfile.FigFile/read>@(hObject,eventdata)tree_inspector('open_pb_Callback',hObject,eventdata,guidata(hObject)) 
      Error while evaluating UIControl Callback

      Have you got an idea what is my principal problem?

      Thank you very much for your response.

      Best regards,
      Sebastian

  17. Paul says:

    Hi everybody,

    I am using uitree in a MATLAB-GUI, too. Can you give me an explanation, how it is possible to modify the content of “handles” in the ExpandFcn of uitree. I always have the problem, that the changings are visible when I am in the function call – afterwards they are deleted. Is there a possibility to make changes outside the original GUIDE-Callbacks?

    Thank you & best regards
    Paul

  18. ss says:

    Thanks Yair Altman

    how to rename or change icon to a uitreenode , I try set(jtree.setEditable(true)), but the name can not be modified

    ss

  19. ss says:

    Thanks Yair Altman

    how to rename or change icon to a uitreenode , I try jtree.setEditable(true), but the name can not be modified

    ss

Leave a Reply

Your email address will not be published. Required fields are marked *