In my particular application I want to be able to externally select specific paths on the checkbox tree as well as respond to selection changes mediated by mouse clicks. However, I do not want to trigger a 'selection change' callback when selecting paths externally. Is there a simple way of checking from inside the 'selection change' callback (which is activated when a selection change occurs) to determine whether the change resulted from an external path selection call (in the code below produced by the radio button activation) or from a mouse click over a checkbox.
I've tried a couple of adhoc solutions, e.g. using an additional callback to respond to mouse clicks over the checkbox tree but this doesn't seem very reliable, sometimes the events are captured and sometimes missed. I've also tried making use of gcbo to get information regarding the current callback object but this always refers to the checkbox tree, I guess becuase activating the radio button triggers the selection change callback associated with the checkbox tree.
The code below is intended to illustrate the problem. A simple check box tree is defined and the selection of the path 'objects/door' is placed under the control of a radiobutton. Toggling the radio button and clicking on to checkboxes directly both trigger the selection change callback. I would like to be able to separate these two events.
Any advice much appreciated. Best wishes,
John
function javaCallbackExp3
import javax.swing.tree.*;
import javax.swing.*;
import com.jidesoft.swing.CheckBoxTree.*
% define a simple tree
rootNode = DefaultMutableTreeNode( 'Objects' );
fNode = DefaultMutableTreeNode( 'window' );
rootNode.add( fNode );
sNode = DefaultMutableTreeNode( 'door' );
rootNode.add( sNode );
% define tree model
treeModel = DefaultTreeModel( rootNode );
% checkbox tree
tree = com.jidesoft.swing.CheckBoxTree( treeModel );
% define tree selection model
treeSelectionModel = tree.getCheckBoxTreeSelectionModel();
% create handle to java object callback properties
hTreeSelectionModel = handle( treeSelectionModel, 'CallbackProperties' );
% set appropriate callback
set( hTreeSelectionModel, 'ValueChangedCallback', @selectionChanged_cb );
% place tree on figure
fh = figure( 'windowStyle', 'docked' );
jScrollPane = com.mathworks.mwswing.MJScrollPane(tree);
[jComp,hc ] = javacomponent(jScrollPane,[10,10,300,150],fh);
% create tree selection button
hButton = uicontrol('style', 'radiobutton',...
'units', 'normalized',...
'string', 'select door',...
'position', [0.5 0.5 0.3 0.2 ],...
'callback', @radioButtonCallback );
% define door selection path for use in radiobutton callback
pathNew = javax.swing.tree.TreePath( [ rootNode fNode ] );
function radioButtonCallback( hObject, ev )
% if radio button set then select (door) path
if get( hObject, 'value' )
treeSelectionModel.setSelectionPath( pathNew );
% otherwise deselect all paths
else
treeSelectionModel.clearSelection;
end
end
function selectionChanged_cb( varargin )
disp( 'selection changed' );
end
end
You can programmatically set a flag in the about-to-be-selected node's UserData or ApplicationData just before selecting it, and then check for this flag (and clear it) within your NodeSelectedCallback. Mouse and keyboard selections will obviously not have the flag set when the callback is triggered. Simple and effective.
I would also suggest checking com.mathworks.mwswing.checkboxtree.CheckBoxTree. This is a built-in Matlab component that is similar yet unrelated to the JIDE component. Example:
% Prepare the tree nodes
import com.mathworks.mwswing.checkboxtree.*
jRoot = DefaultCheckBoxNode('Root');
l1a = DefaultCheckBoxNode('Letters'); jRoot.add(l1a);
l1b = DefaultCheckBoxNode('Numbers'); jRoot.add(l1b);
l2a = DefaultCheckBoxNode('A'); l1a.add(l2a);
l2b = DefaultCheckBoxNode('b'); l1a.add(l2b);
l2c = DefaultCheckBoxNode('<html><b>α'); l1a.add(l2c);
l2d = DefaultCheckBoxNode('<html><i>β'); l1a.add(l2d);
l2e = DefaultCheckBoxNode('3.1415'); l1b.add(l2e);
% Present the standard MJTree:
jTree = com.mathworks.mwswing.MJTree(jRoot);
jScrollPane = com.mathworks.mwswing.MJScrollPane(jTree);
[jComp,hc] = javacomponent(jScrollPane,[10,10,120,110],gcf);
% Now present the CheckBoxTree:
jCheckBoxTree = CheckBoxTree(jTree.getModel);
jScrollPane = com.mathworks.mwswing.MJScrollPane(jCheckBoxTree);
[jComp,hc] = javacomponent(jScrollPane,[150,10,120,110],gcf);
Yair Altman
http://UndocumentedMatlab.com
> I would also suggest checking com.mathworks.mwswing.checkboxtree.CheckBoxTree. This is a built-in Matlab component that is similar yet unrelated to the JIDE component. Example:
More information and alternatives to CheckBoxTree can be found here: http://undocumentedmatlab.com/blog/customizing-uitree-nodes-2/
Yair Altman
http://UndocumentedMatlab.com
Thanks for your advice. I've had a go at using a simple state variable and this works fine, enabling me to determine where node selections derive from (javaCallbackExp5, below). I did find that when using this approach it was important to include a short pause after setting the new selection path to ensure that the selection change callback had time to execute before resetting the state.
I also had a quick play with the checkboxTreeModel you reccommended (com.mathworks.mwswing.checkboxtree.CheckBoxTree). However, I found that when using a selectionModel to highlight particular paths the nodes were not checked even though the paths appear in the selection model (javaCallbackExp6, below).
Thanks again for your help.
Best wishes,
John
function javaCallbackExp5
state = 0;
import javax.swing.tree.*;
import javax.swing.*;
import com.jidesoft.swing.CheckBoxTree.*
% define a simple tree
rootNode = DefaultMutableTreeNode( 'Objects' );
fNode = DefaultMutableTreeNode( 'window' );
rootNode.add( fNode );
sNode = DefaultMutableTreeNode( 'door' );
rootNode.add( sNode );
% define tree model
treeModel = DefaultTreeModel( rootNode );
% tree
tree = com.jidesoft.swing.CheckBoxTree( treeModel );
treeSelectionModel = tree.getCheckBoxTreeSelectionModel();
% create handle to java object callback properties
hTreeSelectionModel = handle( treeSelectionModel, 'CallbackProperties' );
% set appropriate callback
set( hTreeSelectionModel, 'ValueChangedCallback', {@selectionChanged_cb} );
pathNew = javax.swing.tree.TreePath( [ rootNode sNode ] );
hTreeSelectionModel.setSelectionPath( pathNew );
% place tree on figure
fh = figure( 'windowStyle', 'docked' );
jScrollPane = com.mathworks.mwswing.MJScrollPane(tree);
[jComp,hc ] = javacomponent(jScrollPane,[10,10,300,150],fh);
set(fh, 'userdata', 0 );
hButton = uicontrol( 'style', 'pushbutton',...
'units', 'normalized',...
'position', [ 0.5 0.3 0.3 0.1 ],...
'string', 'default selection',...
'callback', @pushbuttonCallback );
hButton3 = uicontrol( 'style', 'pushbutton',...
'units', 'normalized',...
'position', [ 0.5 0.1 0.3 0.1 ],...
'enable','off',...
'string', 'update...',...
'callback', @pushbutton3Callback );
pathNew = javax.swing.tree.TreePath( [ rootNode sNode ] );
function pushbuttonCallback( hObject, ev )
% restore default selection
state=1;
hTreeSelectionModel.setSelectionPath( pathNew );
pause(0.01);
state=0;
end
function pushbutton3Callback( hObject, ev )
% disable update button
set( hObject, 'enable', 'off' );
end
function selectionChanged_cb( varargin )
% if selection changed manually then enable update button
if state
set( hButton3, 'enable', 'off' );
else
set( hButton3, 'enable', 'on' );
end
end
end
function javaCallbackExp6
import com.mathworks.mwswing.checkboxtree.*
jRoot = DefaultCheckBoxNode('Root');
l1a = DefaultCheckBoxNode('Letters'); jRoot.add(l1a);
l1b = DefaultCheckBoxNode('Numbers'); jRoot.add(l1b);
l2a = DefaultCheckBoxNode('A'); l1a.add(l2a);
l2b = DefaultCheckBoxNode('b'); l1a.add(l2b);
l2c = DefaultCheckBoxNode('<html><b>?'); l1a.add(l2c);
l2d = DefaultCheckBoxNode('<html><i>?'); l1a.add(l2d);
l2e = DefaultCheckBoxNode('3.1415'); l1b.add(l2e);
fh = figure( 'windowStyle', 'docked' );
jTree = com.mathworks.mwswing.MJTree(jRoot);
jCheckBoxTree = CheckBoxTree(jTree.getModel);
jScrollPane = com.mathworks.mwswing.MJScrollPane(jCheckBoxTree);
[jComp,hc] = javacomponent(jScrollPane,[150,10,120,110],gcf);
% get selection model
treeSelectionModel = jCheckBoxTree.getSelectionModel();
% define a path
path = javax.swing.tree.TreePath( [ jRoot l1a ] )
% select path
treeSelectionModel.setSelectionPath( path );
% recover selected path
treeSelectionModel.getSelectionPath
end