- Undocumented Matlab - https://undocumentedmatlab.com -

Tri-state checkbox

Posted By Yair Altman On October 19, 2011 | 5 Comments

When presenting information visually in graphical user interfaces (GUIs), we often need to present and enable interaction with state data (such as On/Off). In most cases, we would naturally use a checkbox to present the information and enable interaction. But What can we do if the data has three possible states. For example, Yes/No/Maybe, or: Full/Empty/Partial, or: Up/Down/Undetermined ?
Until today, Matlab GUIs had to resort to using drop-down (aka combo-box or popup-menu) or radio-button controls to present such information. However, would it not be nicer if we could still use a checkbox? Outside Matlab, such a control is known as a tri-state checkbox and many modern GUI frameworks support it. Well, surprise surprise, so does Matlab (although you would never guess it from the documentation).

CheckBoxTree

Last year, I have already described [1] a built-in Matlab tree control whose nodes have tri-state checkboxes:

a regular MJTree (left) and a CheckBoxTree (right)
a regular MJTree (left) and a CheckBoxTree (right)

Today I will show how we can use these checkboxes as independent GUI controls.

Modifying the standard Matlab checkbox uicontrol

In order to modify the standard Matlab checkbox uicontrol, we need to first get its underlying Java component reference. This is done using the findjobj utility [2]. We then update its UI wrapper to be the same as the CheckBoxTree‘s checkbox control.
To programmatically set a mixed state we update the ‘selectionState’ client property to SelectionState.MIXED (SelectionState also has the SELECTED and NOT_SELECTED values).
Here is an end-to-end example:

hCB = uicontrol('Style','checkbox', ...);
jCB = findjobj(hCB);
jCB.setUI(com.mathworks.mwswing.checkboxtree.TriStateButtonUI(jCB.getUI));
% Update the checkbox state to MIXED
newState = com.mathworks.mwswing.checkboxtree.SelectionState.MIXED;
jCB.putClientProperty('selectionState', newState);
jCB.repaint;

Matlab checkboxes displaying mixed states
Matlab checkboxes displaying mixed states

Displaying as an independent Java control

Instead of retrofitting a standard Matlab uicontrol as described above, we can directly use the standard javax.swing.JCheckBox which does not normally support tri-state (it only has two states), displaying it in our GUI with the built-in javacomponent function [3]:

% Display the checkbox (UNSELECTED state at first)
jCB = javax.swing.JCheckBox('JCheckBox - mixed',0);
javacomponent(jCB, [10,70,150,20], gcf);
% Update the checkbox state to MIXED
import com.mathworks.mwswing.checkboxtree.*
jCB.setUI(TriStateButtonUI(jCB.getUI));
jCB.putClientProperty('selectionState', SelectionState.MIXED);
jCB.repaint;

Note that instead of using javax.swing.JCheckBox, we could use the internal Matlab class com.mathworks.mwswing.MJCheckBox, which directly extends JCheckBox and adds mnemonic (shortcut-key) support, but is otherwise fully compatible with JCheckBox. Actually, it is MJCheckBox which is the underlying Java component of the standard Matlab checkbox uicontrol.

Alternative controls

Now that we have seen that Matlab includes built-in support (well, at least support in the technical sense, not the official customer-support sense), would you be surprised to learn that it includes similar support in other internal components as well?
The internal Matlab class com.mathworks.mwt.MWCheckbox directly supports a tri-state (yes/no/maybe) checkbox, without any need to update its UI, as follows:

% Display the checkbox (UNSELECTED state at first)
jCB = com.mathworks.mwt.MWCheckbox('MWCheckbox - mixed',0);
javacomponent(jCB, [10,70,150,20], gcf);
% Update the checkbox state to MIXED
jCB.setMixedState(true);
% Retrieve the current state
isMixedFlag = jCB.isMixedState();  % true/false

MJCheckBox vs. MWCheckbox
MJCheckBox vs. MWCheckbox

Note that the State property, which controls the standard selected/unselected state, is entirely independent from the MixedState property. Both State and MixedState are boolean properties, so to get the actual checkbox state we need to query both of these properties.
Another internal Matlab class that we can use is JIDE’s com.jidesoft.swing.TristateCheckBox (which is pre-bundled in Matlab and is fully documented here [4]).
There are many other tri-state checkbox alternatives available online (for example, here [5], here [6] and here [7]). We can easily include them in our Matlab GUI with the javacomponent function. Using external components we can be more certain of the compatibility issues in past and future Matlab releases. On the other hand, internal Matlab classes do have the advantage of being inherently accessible on all platforms of the same Matlab release, whereas non-Matlab components must be included in our deployment package.
Do you use any tri-state controls, either Matlab or external, in your work? If so, please share your experience in a comment below [8].

Categories: GUI, Java, Medium risk of breaking in future versions, UI controls, Undocumented feature


5 Comments (Open | Close)

5 Comments To "Tri-state checkbox"

#1 Comment By weiliang On November 18, 2011 @ 12:20

I have tried all three approaches.
The first one, Modifying the standard Matlab checkbox uicontrol, has little change to my existing code, but the call to findjobj is too expansive and time consuming (i have more than 10 checkboxes).
Both Displaying as an independent Java control and Alternative controls will have no performance problem. but I have difficulty to add callbacks to the jCheckbox.
Also all three seem have drawing problem when is in third state (partial check state).
Can someone comment on this. Code sample for how to add callback to the last two methods is greatly appreciated.

#2 Comment By Yair Altman On November 19, 2011 @ 09:04

@weiliang – Java controls have some ~30 standard callbacks that you can set, ranging from mouse and keyboard events, through property and hierarchy changes, plus several callbacks that are specific to the control. Try setting the StateChangedCallback and ItemStateChangedCallback. More on Java component callbacks can be found [15] and in sections 3.4 and 6.4 of my [16].

#3 Comment By Pecus On December 16, 2012 @ 09:18

@Yair – Thanks for all the advice here! Just discovering all these mysteries…

I’m having difficulties (probably the same as weilang had) disabling the mixed state of JCheckBox. If it has not been in mixed state, then I can toggle its state and appeareance (selected or deselected) by clicking. But soon as I put it in mixed state, changing the state by clicking does not affect its appeareance.
Also I could not find the method for setting the state of JCheckBox to selected/deselected. For MWCheckbox it is “jCB.setSelected(1)” (or “0”).
To put it in a nutshell:
1. What is the opposite of “jCB.putClientProperty(‘selectionState’, SelectionState.MIXED);”?
2. What is the counterpart of “jCB.setSelected(1)”?

Third problem: I wrote a Callback function to switch on or off all subordinated checkboxes, if my JCheckBox has been clicked: (Still only works when not in mixed mode.)

function Tristatecheckbox_Callback(hObject,eventdata,subCBs) % subCBs as CELL
isSelected=hObject.isSelected;
n=size(subCBs);
for i=1:n(2)
   set(subCBs{i},'Value',isSelected);
end

Now my problem is where/when to associate this function with Java Callbacks.
I wrote this code snippet, which is working:

hjCB = handle(handles.jCB,'CallbackProperties'); % initialised with "handles.jCB = javax.swing.JCheckBox(..."
subCBs={handles.CB1,handles.CB2,handles.CB3};
set(hjCB,'ItemStateChangedCallback',{@Tristatecheckbox_Callback,subCBs});

First I put it right after the JCheckBox’s creation, which is in the CreateFcn of a panel. But in CreateFcns there are no visible handles but those of the object in creation, so handles.CB1 can not be allocated.
For trial&error, I put it in the CallbackFcn of a dummy pushbutton and just clicked this dummy before using the rest, but later I need this snippet to be done before the user can do anything with the GUI.
3. Is there a function running right after the GUI is created, with access to all the handles? Which one? And if no, where else to put the code?

Thanks a lot!

#4 Comment By Yair Altman On December 16, 2012 @ 10:56

@Pecus –

The possible com.mathworks.mwswing.checkboxtree.SelectionState values are: MIXED, NOT_SELECTED and SELECTED, which are pretty-much self-explanatory.

I assume that you are using GUIDE to create your GUI. In such a case, the *_OutputFcn() function is called after the entire GUI is created, immediately before the control is passed to the user. In this function, you have access to all handles. See [17].

#5 Comment By Dhanya Pradeep On February 15, 2016 @ 11:59

Hi Yair,
I’m trying to use the com.mathworks.mwswing.checkboxtree in my MATLAB application. I’m trying all sorts of methods for handling the actions on enabling and disabling the checkbox node. Unfortunately I’m not getting the right callback to be used for handling the action based on the toggling of the checkbox. Could you give me some hint on the solution.

Thanks,
Dhanya


Article printed from Undocumented Matlab: https://undocumentedmatlab.com

URL to article: https://undocumentedmatlab.com/articles/tri-state-checkbox

URLs in this post:

[1] described: http://undocumentedmatlab.com/blog/customizing-uitree-nodes-2/#Built-in-classes

[2] findjobj utility: http://undocumentedmatlab.com/blog/findjobj-find-underlying-java-object/

[3] javacomponent function: http://undocumentedmatlab.com/blog/javacomponent/

[4] here: http://www.jidesoft.com/javadoc/com/jidesoft/swing/TristateCheckBox.html

[5] here: https://forums.oracle.com/forums/search.jspa?threadID=&q=%28tri-state+OR+tristate%29+AND+checkbox&objID=c285&dateRange=all&userID=&numResults=30&rankBy=10001

[6] here: http://www.javaspecialists.eu/archive/Issue145.html

[7] here: http://stackoverflow.com/questions/1263323/tristate-checkboxes-in-java

[8] comment below: http://undocumentedmatlab.com/blog/tri-state-checkbox/#respond

[9] Unorthodox checkbox usage : https://undocumentedmatlab.com/articles/unorthodox-checkbox-usage

[10] Determining axes zoom state : https://undocumentedmatlab.com/articles/determining-axes-zoom-state

[11] Recovering previous editor state : https://undocumentedmatlab.com/articles/recovering-previous-editor-state

[12] CheckboxList : https://undocumentedmatlab.com/articles/checkboxlist

[13] Font selection components : https://undocumentedmatlab.com/articles/font-selection-components

[14] FindJObj GUI – display container hierarchy : https://undocumentedmatlab.com/articles/findjobj-gui-display-container-hierarchy

[15] : https://undocumentedmatlab.com/blog/uicontrol-callbacks/

[16] : https://undocumentedmatlab.com/matlab-java-book/

[17] : http://www.mathworks.com/help/matlab/creating_guis/initializing-a-guide-gui.html

Copyright © Yair Altman - Undocumented Matlab. All rights reserved.