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 a built-in Matlab tree control whose nodes have tri-state checkboxes:
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. 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; |
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:
% 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 |
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).There are many other tri-state checkbox alternatives available online (for example, here, here and here). 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.
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.
@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 here and in sections 3.4 and 6.4 of my Matlab-Java book.
@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.)
Now my problem is where/when to associate this function with Java Callbacks.
I wrote this code snippet, which is working:
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!
@Pecus –
The possible
com.mathworks.mwswing.checkboxtree.SelectionState
values are:MIXED
,NOT_SELECTED
andSELECTED
, 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 this doc-page.
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