Last week a reader on the CSSM newsgroup asked whether it is possible to programmatically deselect all listbox items. By default, Matlab listboxes enable a single item selection: trying to deselect it interactively has no effect, while trying to set the listbox’s Value property to empty ([]) results in the listbox disappearing and a warning issued to the Matlab console:
>> hListbox = uicontrol('Style','list', 'String',{'item #1','item #2','item #3','item #4','item #5','item #6'}); >> set(hListbox,'Value',[]); Warning: Single-selection 'listbox' control requires a scalar Value. Control will not be rendered until all of its parameter values are valid (Type "warning off MATLAB:hg:uicontrol:ValueMustBeScalar" to suppress this warning.)
The reader’s question was whether there is a way to bypass this limitation so that no listbox item will be selected. The answer to this question was provided by MathWorker Steve(n) Lord. Steve is a very long-time benefactor of the Matlab community with endless, tireless, and patient advise to queries small and large (way beyond the point that would have frustrated mere mortals). Steve pointed out that by default, Matlab listboxes only enable a single selection – not more and not less. However, when the listbox’s Max value is set to be >1, the listbox enables multiple-items selection, meaning that Value accepts and reports an array of item indices, and there is nothing that prevents this array from being empty (meaning no items selected):
>> hListbox = uicontrol('Style','list', 'Max',2, 'String',{'item #1','item #2','item #3','item #4','item #5','item #6'}); >> set(hListbox,'Value',[]); % this is ok - listbox appears with no items selected
Note: actually, the listbox checks the value of Max–Min, but by default Min=0 and there is really no reason to modify this default value, just Max.
While this makes sense if you think about it, the existing documentation makes no mention of this fact:
The Max property value helps determine whether the user can select multiple items in the list box simultaneously. If Max – Min > 1, then the user can select multiple items simultaneously. Otherwise, the user cannot select multiple items simultaneously. If you set the Max and Min properties to allow multiple selections, then the Value property value can be a vector of indices.
Some readers might think that this feature is not really undocumented, since it does not directly conflict with the documentation text, but then so are many other undocumented aspects and features on this blog, which are not mentioned anywhere in the official documentation. I contend that if this feature is officially supported, then it deserves an explicit sentence in the official documentation.
However, the original CSSM reader wanted to preserve Matlab’s single-selection model while enabling deselection of an item. Basically, the reader wanted a selection model that enables 0 or 1 selections, but not 2 or more. This requires some tweaking using the listbox’s selection callback:
set(hListbox,'Callback',@myCallbackFunc); ... function test(hListbox, eventData) value = get(hListbox, 'Value'); if numel(value) > 1 set(hListbox, 'Value', value(1)); end end
…or a callback-function version that is a bit better because it takes the previous selection into account and tries to set the new selection to the latest-selected item (this works in most cases, but not with shift-clicks as explained below):
function myCallbackFunc(hListbox, eventData) lastValue = getappdata(hListbox, 'lastValue'); value = get(hListbox, 'Value'); if ~isequal(value, lastValue) value2 = setdiff(value, lastValue); if isempty(value2) setappdata(hListbox, 'lastValue', value); else value = value2(1); % see quirk below setappdata(hListbox, 'lastValue', value); set(hListbox, 'Value', value); end end end
This does the job of enabling only a single selection at the same time as allowing the user to interactively deselect that item (by ctrl-clicking it).
There’s just a few quirks: If the user selects a block of items (using shift-click), then only the second-from-top item in the block is selected, rather than the expected last-selected item. This is due to line #9 in the callback code which selects the first value. Matlab does not provide us with information about which item was clicked, so this cannot be helped using pure Matlab. Another quirk that cannot easily be solved using pure Matlab is the flicker that occurs when the selection changes and is then corrected by the callback.
We can solve both of these problems using the listbox’s underlying Java component, which we can retrieve using my findjobj utility:
% No need for the standard Matlab callback now set(hListbox,'Callback',[]); % Get the underlying Java component peer jScrollPane = findjobj(h); jListbox = jScrollPane.getViewport.getView; jListbox = handle(jListbox,'CallbackProperties'); % enable callbacks % Attach our callback to the listbox's Java peer jListbox.ValueChangedCallback = {@myCallbackFunc, hListbox}; ... function myCallbackFunc(jListbox, eventData, hListbox) if numel(jListbox.getSelectedIndices) > 1 set(hListbox, 'Value', jListbox.getLeadSelectionIndex+1); % +1 because Java indices start at 0 end end
We can use a similar mechanism to control other aspects of selection, for example to enable only up to 3 selections but no more etc.
We can use this underlying Java component peer for a few other useful selection-related hacks: First, we can use the peer’s RightSelectionEnabled property or setRightSelectionEnabled() method to enable the user to select by right-clicking listbox items (this is disabled by default):
jListbox.setRightSelectionEnabled(true); % false by default set(jListbox,'RightSelectionEnabled',true); % equivalent alternative
A similarly useful property is DragSelectionEnabled (or the corresponding setDragSelectionEnabled() method), which is true by default, and controls whether the selection is extended to other items when the mouse drags an item up or down the listbox.
Finally, we can control whether in multi-selection mode we enable the user to only select a single contiguous block of items, or not (which is Matlab’s default behavior). This is set via the SelectionMode property (or associated setSelectionMode() method), as follows:
jListbox.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION); jListbox.setSelectionMode(1); % equivalent alternative (less maintainable/readable, but simpler)
![]() | ![]() | ![]() |
SINGLE_SELECTION =0 | SINGLE_INTERVAL_SELECTION =1 | MULTIPLE_INTERVAL_SELECTION =2 |
(Matlab default for Max=1) | (only possible with Java) | (Matlab default for Max>1) |
Additional listbox customizations can be found in related posts on this blog (see links below), or in section 6.6 of my Matlab-Java Programming Secrets book (which is still selling nicely almost five years after its publication, to the pleasant surprise of my publisher…).