In previous articles, I explained how we can use findjobj to customize a Matlab uicontrol’s underlying Java control, thereby improving its appearance and functionality. My two previous articles on the Matlab editbox were a classic example of this mechanism. Unfortunately, this technique does not always work well, and an alternative mechanism needs to be used. One such case in point is the subject of today’s article.
Matlab combo-box (a.k.a. “popup-menu” or “drop-down”) controls are very simple controls that accept a list of strings from which a user can select. This is a very simple control that answers a wide range of use-cases. Unfortunately, it is quite limited. Among other limitations, we cannot modify the popup-panel’s appearance/functionality; we cannot select multiple items; and we cannot type-in a value in the control’s editbox. Today’s article will focus on the latter limitation, namely how to use an editable combo-box.
Trying to make Matlab’s standard combobox editable
We can indeed use findjobj to get a Matlab combo-box’s underlying Java control. This turns out to be a com.mathworks.hg.peer.ComboboxPeer$MLComboBox
object, which extends the standard Java Swing JComboBox:
>> hCombo = uicontrol('Style','popup', 'String',{'a','b','c'}); >> jCombo = findjobj(hCombo) jCombo = javahandle_withcallbacks.com.mathworks.hg.peer.ComboboxPeer$MLComboBox |
This jCombo
control has the Editable property that we can then try to override (the default value is false
):
>> jCombo.setEditable(true); >> jCombo.Editable = true; % equivalent alternative >> set(jCombo,'setEditable',true); % equivalent alternative |
The bad news is that the moment we enter some value (as in the screenshot here) that is not already a member of the pop-up panel (i.e., the cell-array in the String property), then the control disappears and a warning message is issued to the Matlab console:
Warning: popupmenu control requires that Value be an integer within String range Control will not be rendered until all of its parameter values are valid (Type "warning off MATLAB:hg:uicontrol:ParameterValuesMustBeValid" to suppress this warning.) |
The reason for this behavior is that when the combo-box object detects that the text field’s content match none of the popup list items, it automatically sets jCombo
‘s SelectedIndex to -1 and Matlab’s corresponding HG Value property to 0. At this point the Matlab implementation kicks in, hiding the uicontrol since it considers 0 an invalid value for the Value property. This is similar to the check being done to test for an empty HG String value (=no items):
>> set(hCombo, 'string', []) popupmenu control requires a non-empty String Control will not be rendered until all of its parameter values are valid. |
We can clear these particular warnings via:
warning('off','MATLAB:hg:uicontrol:ParameterValuesMustBeValid') |
but this does not prevent the control from being hidden – it just prevents the warning from showing on the Command Window.
We can dive deeper and try to modify the underlying data model and disassociate the Java control from HG, but let’s stop at this point since there is really no point considering the fact that there is a much simpler alternative.
Note: if you do decide to make the standard Matlab uicontrol editable, read here for a related customization that I posted several years ago.
The pure-Java alternative
Rather than customizing Matlab’s uicontrol, we can easily create an identical-looking control using the standard Java Swing JComboBox, which has none of these problems/limitations. We can create and display the component in one go using the semi-documented javacomponent function:
position = [10,100,90,20]; % pixels hContainer = gcf; % can be any uipanel or figure handle options = {'a','b','c'}; model = javax.swing.DefaultComboBoxModel(options); jCombo = javacomponent('javax.swing.JComboBox', position, hContainer);jCombo.setModel(model);jCombo.setEditable(true); |
We can use a variant of javacomponent to create the component with the model in one go, replacing the highlighted lines above:
jCombo = javacomponent({'javax.swing.JComboBox',model}, position, hContainer); |
Once we have the control ready, all we need to do is set its ActionPerformedCallback property to our Matlab callback function and we’re pretty-much set. We can get the currently-selected text using char(jCombo.getSelectedItem)
and the selected list index (0-based) using jCombo.getSelectedIndex
(which returns -1 if we entered a non-listed value, 0 for the first list item, 1 for the second etc.). More information can be found here.
Lesson learnt
In the past 20+ years of my professional life as engineer and development manager, my number one rule has always been:
But sometimes, we should also remember an alternative version:
Available report – “Advanced Customizations of Matlab Uicontrols”
Interested readers can find more information about these and other possible customizations in my report on “Advanced Customizations of Matlab Uicontrols“. This 90-page PDF report can be purchased here ($29, please allow 24 hours for delivery by email). The report explains how to customize Matlab’s uicontrols in ways that are simply not possible using documented Matlab properties. This includes treatment of push buttons, toggle buttons, radio buttons, checkboxes, editboxes, listboxes, popup menus (aka combo-boxes/drop-downs), sliders, labels, and tooltips. Much of the information in the report is also available in hard-copy format in chapter 6 of my Matlab-Java programming book.
shalom Yair,
first of all – I enjoy your fruitfull and interesting ideas
second, regarding the editable combobox – is there a way to search the list as one types the words ‘online’ so he needs not scroll the whole list. i have a list of over 3000 to search…
best
moshe
@Moshe – you can either update the combo’s list items in the control’s KeyTypedCallback, or use a dedicated control that does it for you. One example is Matlab’s internal
com.mathworks.widgets.AutoCompletionList
, but this component does not exist in all Matlab releases.I explain this and other alternatives in pages 296-297 and 407-416 of my book.
shalom Yair,
as i struggle with the AutoCompletionList, a few questions are arised:
1. how do i retrieve the value, string one chooses?
2. can it be modified to look and behave like combobox?
looking forward to hearing from you…
moshe
another questions
is there a way to search with wild cards and make the list shorter, as the user types the search?
@Moshe – I do not have additional information to what I wrote above and in my book. I’m afraid that you will need to investigate this by yourself for the time being, since I do not plan to write an article about this in the foreseeable future, sorry.
I succeeded thanks to your suggestion to make use of the various optional Callbacks, when i’m done with the code i’ll be glad to publish it here
Hi, Yair,
“you can either update the combo’s list items in the control’s KeyTypedCallback”
I tried set the jCombo’s KeyTypeCallback property, but it does not work:
could you explain more details, thanks so much.
@Steven – You need to specify the KeyTypedCallback on the combo-box’es editbox (text-field) sub-component, not on the top-level component. Namely:
Hi Yair,
I was trying to use a ◾TreeComboBox in my GUI, but it seems something is wrong:
What’s wrong exactly?
Hi Yair
Firstly, thank you for your website.
I found a lot of useful hints from your website.
At this time, I try to call a MATLAB function when an item was selected in combo box’s drop down list. (mouse or up/down key pressed)
I know I can do that in Java by adding ‘addactionlistener’ or ‘additemlistener’.
How can I do the same job in MATLAB GUI?
Thanks,
King
@King –
Thanks! It works!
Before I saw your solution, I figure out I can use KeyReleasedCallBack as my callback property
However, it still not solve the mouse click issue.
Your one get the job done perfectly!
Furthermore, instead of clicking mouse on the item, moving mouse on item then fire the callback?
I tried jCombo.getcomponent(2) and added mouselistener, but it doesn’t help.
Maybe I am in a right approach but missing some lines?
Thanks!
Hi Yair
set(jCombo, ‘ActionPerformedCallback’, @myCallbackFcn)
This commandline can handle the callback.
But I want to handle the user input more precisely.
I try to hear ‘Up’ ‘Down’ ‘Enter’key pressed or mouse left click.
Therefore, I can assign different function to different user input.
Is it possible to do that in combo box? If so, how?
Thanks a lot.
@King – see my answer above to Steven Tsai.
Hi Yair,
Thanks for the great information. However I want to ask if I have two combobox, how can I put them inside one figure instead of two?
Meanwhile, if I want to have a label for each combbox. How can I do that? I checked around, did not find anything about that.
Thanks.
@Buer – you can use the Position property of the uicontrol to place it anywhere in your figure, and place separate uicontrols in separate locations. You can use other calls to uicontrol to place text labels. Look it up in the documentation.
I created a plotter using three popup menus: one for X-variable, one for Y, and one for a figure name. When a figure name (number) is selected, its callback function grabs strings from X and Y popup menus, search these from a loaded dataset, and plots them.
What I want to do is multiple-selection on a popup menu. I researched quite a bit and learned that popup menu doesn’t have that capability as you also mentioned on the top in the regular documented way.
The reason why I don’t want and almost can’t use list box is my GUI has many panels from top to bottom; each containing the three popup menus mentioned above. Each panel represents one dataset. This means if I select and load ten .MAT files, a GUI will be created with 10 panels from top to bottom. Each dataset can have as many as 100 or more variables. Unless I completely scrub the current GUI generation code, listbox won’t work. Say each listbox shows ten variables and a scroll bar. The height of it and some margins above and below times 10 will create a gigantic GUI that will be basically unusable.
Do you know a work-around? Thank you in advance.
@Eric – you can integrate a
com.jidesoft.combobox.MultiSelectListComboBox
orMultilineStringComboBox
. If you need consulting assistance, contact me by email.Hi Yair,
How can I use JIDE’s DateComboBox as the celleditor for a column in a jide table? So basically a table column having a combobox dropdown as a date selector(calendar), I have set the column class as date and made it to accept different date formats, but couldn’t get calendar dropdown to work in a table.
Thanks,
Amit