Is it possible to disable/change the default selection logic of CheckBoxTree?

18 views (last 30 days)
When checking/unchecking nodes in a CheckBoxTree, the following rules are applied (from CheckBoxTree Properties documentation):
  1. If CheckedNodes contains a parent node, all the children of the parent node are automatically added to CheckedNodes.
  2. If CheckedNodes contains all the children of a parent node, the parent node is automatically added to CheckedNodes.
While I appreciate the first rule, the second one makes this UI element unusable for me.
I would like to know if there is a way to either change these rules (e.g. disable rule 2) or disable them so I can implement my own in CheckedNodesChangedFcn callback. When modifying the CheckedNodes property of CheckBoxTree programmatically, these rules are applied as well, so just modifying that list is not a workaround unfortunately.

Answers (2)

Mario Malic
Mario Malic on 3 Nov 2023
Edited: Mario Malic on 3 Nov 2023
As it is now, it is impossible. Parent nodes will always be selected if all child nodes are. I have made a callback function and this is silly that it's impossible to do it. If it's helpful, you can use normal uitree use multiselect option, as this is the one that doesn't trigger the parent selection.
function treeCheckedNodesChangedFcn(src, evt)
if ~isempty(src.CheckedNodes)
% Find all nodes
allNodes = findall(src, "Type", "uitreenode");
% Find parent indices to remove
parentCheckedNodes = evt.ParentCheckedNodes;
parentIdx = ismember(allNodes, parentCheckedNodes);
% Find children indices and remove parent indices
selectedCheckedNodes = evt.CheckedNodes;
selectedChildrenNodesIdx = ismember(selectedCheckedNodes, parentCheckedNodes);
childrenNodes = selectedCheckedNodes(~selectedChildrenNodesIdx);
nodeChildrenIdx = ismember(allNodes, childrenNodes);
src.CheckedNodes = allNodes(nodeChildrenIdx);
end
end
Maybe this would be interesting for you @Adam Danz

Adam Danz
Adam Danz on 3 Nov 2023
Edited: Adam Danz on 3 Nov 2023
As @Mario Malic mentioned, it's not possible to replace that logic. I'm curious what your use case is as to why the value of the parent node should not indicate the collective state of its children nodes. We may be able to come up with a more targetted workaround if we understand how you're using the checkbox tree and why the value of the parent should be independent to the values of its children.
It's fairly easy to detect when a parent was auto selected or auto deselected. In this demo below, any time a parent's value is changed automatically, a statment is printed to the MATLAB command window indicating the parent name and whether it was auto selected or auto deselected. The CheckedNodesChangedFcn would have to be appended if you wanted to store those values between calls.
%% Create checkbox tree
fig = uifigure;
t = uitree(fig,'Checkbox',"Position",[20 20 150 150]);
t.CheckedNodesChangedFcn = @treeCheckedNodesChangedFcn;
% First level nodes
category1 = uitreenode(t,"Text","Runners","NodeData",[]);
category2 = uitreenode(t,"Text","Cyclists","NodeData",[]);
% Second level nodes.
% Node data is age (y), height (m), weight (kg)
p1 = uitreenode(category1,"Text","Joe","NodeData",[40 1.67 58] );
p2 = uitreenode(category1,"Text","Linda","NodeData",[49 1.83 90]);
p3 = uitreenode(category2,"Text","Rajeev","NodeData",[25 1.47 53]);
p4 = uitreenode(category2,"Text","Anne","NodeData",[88 1.92 100]);
% Expand the tree
expand(t);
function treeCheckedNodesChangedFcn(src, evt)
% Display a message in the command window when a parent is automatically
% selected or de-deselected.
selectedNode = src.SelectedNodes;
parentsChecked = evt.ParentCheckedNodes;
prevParentsChecked = evt.PreviousParentCheckedNodes;
% Auto-selected detection
% If a parent node is in the list of currently selected parents but not in
% the list of previously selected parents, and if the parent node wasn't
% just manually selected by the user, print a statement to the command
% window.
isAutoSelected = ~ismember(parentsChecked, selectedNode) & ~ismember(parentsChecked, prevParentsChecked);
if any(isAutoSelected)
nodeText = get(parentsChecked(isAutoSelected),'Text');
fprintf('%s was auto selected.\n',nodeText)
end
% Auto de-selection detection
% If a parent node is not in the list of currently selected parents but is in
% the list of previously selected parents, and if the parent node wasn't
% just manually de-selected by the user, print a statement to the command
% window.
isAutoDeselected = ~ismember(prevParentsChecked, selectedNode) & ~ismember(prevParentsChecked, parentsChecked);
if any(isAutoDeselected)
nodeText = get(prevParentsChecked(isAutoDeselected),'Text');
fprintf('%s was auto deselected.\n',nodeText)
end
end
  1 Comment
Martin Ammermüller
Martin Ammermüller on 6 Nov 2023
Use Case:
When importing hierarchical data, it shall be possible for a user to only select a subtree of the hierarchy for import.
Example:
In this picture, a user has selected the node "SubTree" for import. To clearly communicate this, only the checkboxes of "SubTree" and its child nodes should be checked. Even if auto selected parents can be determined to correctly set the apps internal state, what is communicated externally through the UI does not match this internal state and is misleading the user.

Sign in to comment.

Categories

Find more on Develop uifigure-Based Apps in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!