Last week I explained how we can use display custom items in a standard Matlab combobox (popup/dropdown), using its underlying Java component. Today I will show how we can use this Java component for other nice customizations of the combobox’s popup:
Underlying Java component
The first step is to find the underlying Java component of the Matlab combobox (aka popup) uicontrol. This is done using my findjobj utility:
% Create the Matlab combobox items = {'<html><font color="red">Hello</font></html>', 'world', ... '<html><font style="font-family:impact;color:green"><i>What a', ... '<html><font color="blue" face="Comic Sans MS">nice day!</font>'}; hCombobox = uicontrol('Style','popup', 'Position',[10,100,120,20], 'String',items); % Find the uicontrol's underlying Java component jCombobox = findjobj(hCombobox); |
For findjobj to work, the Matlab uicontrol needs to be visible – it will not have a Java component before it is rendered onscreen for the first time. If everything is successful, jCombobox should now be a reference to the underlying om.mathworks.hg.peer.ComboboxPeer$MLComboBox
Java component, which is an extension of the standard Swing JComboBox
, as can be seen using my checkClass utility:
>> jCombobox.checkClass private com.mathworks.hg.peer.ComboboxPeer$MLComboBox (uiinspect) Superclass: com.mathworks.mwswing.MJComboBox Superclass: javax.swing.JComboBox Methods in JComboBox missing in ComboboxPeer$MLComboBox: JComboBox() JComboBox(java.lang.Object[]) JComboBox(java.util.Vector) JComboBox(javax.swing.ComboBoxModel) Methods in ComboboxPeer$MLComboBox missing in JComboBox: ComboboxPeer$MLComboBox(com.mathworks.hg.peer.ComboboxPeer) isPopupWidthConstrained() : boolean isTipWhenTruncatedEnabled() : boolean processEvent(java.awt.AWTEvent) registerWithKeyBindingManager(com.mathworks.mwswing.binding.KeyBindingManager, java.lang.String) setConstrainPopupWidth(boolean) setEditorColumnCount(int) setTipWhenTruncatedEnabled(boolean) Methods inherited & modified by ComboboxPeer$MLComboBox: getInsets() : java.awt.Insets setBackground(java.awt.Color) updateUI() Interfaces in JComboBox missing in ComboboxPeer$MLComboBox: java.awt.ItemSelectable java.awt.event.ActionListener javax.accessibility.Accessible javax.swing.event.ListDataListener |
We shall now use three properties of this object to customize the control’s popup:
MaximumRowCount
The MaximumRowCount numeric property (default=20) sets the maximal number of drop-down items to display in the visible portion of the popup, before requiring a scrollbar. This basically controls the popup’s height:
% Get the current MaximumRowCount value numItems = get(jCombobox, 'MaximumRowCount'); numItems = jCombobox.MaximumRowCount; % equivalent - access the property directly numItems = jCombobox.getMaximumRowCount; % equivalent - use Java's accessor method (best way) % Set the MaximumRowCount value set(jCombobox,'MaximumRowCount',3); jCombobox.MaximumRowCount = 3; % equivalent - access the property directly jCombobox.setMaximumRowCount(3); % equivalent - use Java's accessor method (best way) |
Note that MaximumRowCount is a Matlab extension to the standard Swing
JComboBox
, so if we use a JComboBox
directly in our code (using javacomponent) we will not have this feature. Creating the ComboboxPeer$MLComboBox
component instead is possible, but is beyond the scope of this article, because MathWorks chose for this class not to have JComboBox
‘s standard constructors but rather only a constructor that accepts a com.mathworks.hg.peer.ComboboxPeer
object.
PopupVisible
The PopupVisible property (default=false) is a boolean flag which controls whether the popup window is currently (or should be) displayed. If this property is updated, then the focus is automatically transferred to the popup window for easy item selection using the keyboard (up/down/enter keys). There are also equivalent convenience methods showPopup()/hidePopup():
% Is the popup currently shown? isShown = get(jCombobox, 'PopupVisible'); isShown = jCombobox.PopupVisible; % equivalent - access the property directly isShown = jCombobox.isPopupVisible; % equivalent - use Java's accessor method (best way) % Display the popup set(jCombobox,'PopupVisible',true); % NOT 'on' - this is a Java property, not a Matlab HG one! jCombobox.PopupVisible = true; % equivalent - access the property directly jCombobox.setPopupVisible(true); % equivalent - use Java's accessor method (best way) jCombobox.showPopup(); % equivalent - use Java's direct method % Hide the popup set(jCombobox,'PopupVisible',false); % NOT 'off' - this is a Java property, not a Matlab HG one! jCombobox.PopupVisible = false; % equivalent - access the property directly jCombobox.setPopupVisible(false); % equivalent - use Java's accessor method (best way) jCombobox.hidePopup(); % equivalent - use Java's direct method |
Note that PopUpVisible is not a Matlab extension – it exists in the original Swing JComboBox
. Unfortunately, it was not included in the list of properties that are exposed to the user by the high-level Matlab uicontrol, so we need to use the underlying Java component.
On a Windows platform the PopupVisible property is toggled, thereby showing/hiding the popup window, whenever the user clicks <Alt-Up> or <Alt-Down> when the combo-box has focus.
PopupWidthConstrained
The PopupWidthConstrained property (default=false) is a boolean flag which is another Matlab extension to the standard Swing JComboBox
. It is apparently used to constrain the width of the drop-down list to the width of the text field. MathWorks took the trouble to add this feature because Swing JComboBox
‘s width is constrained, causing a difficulty in distinguishing between popup values when the control is relatively narrow; Matlab’s MJComboBox
‘s default unconstrained behavior is much more user-friendly:
Note that the PopupWidthConstrained property’s read accessor methods is the expected isPopupWidthConstrained(), thereby also enabling the expected Matlab-standard format of get(‘PopupWidthConstrained’). However, the property update accessor method is not the expected setPopupWidthConstrained(flag) but rather a non-standard setConstrainPopupWidth(flag). For this reason, it is impossible to set this property using set(‘PopupWidthConstrained’,…), but only via the Java setConstrainPopupWidth() accessor method:
>> set(jCombobox,'PopupWidthConstrained',true) ??? Changing the 'PopupWidthConstrained' property of javahandle_withcallbacks.com.mathworks.hg.peer.ComboboxPeer$MLComboBox is not allowed. >> jCombobox.setPopupWidthConstrained(true) ??? No appropriate method or public field setPopupWidthConstrained for class javahandle_withcallbacks.com.mathworks.hg.peer.ComboboxPeer$MLComboBox. >> jCombobox.setConstrainPopupWidth(true) % this is ok
For additional customizations of Matlab comboboxes, refer to section 6.7 of my Matlab-Java programming book.
R2014b
We’re all eagerly awaiting the much-anticipated R2014b release. As you all know, this is an important release with major functionality and engine improvements. It is therefore not surprising that the release date (which should normally have been September 1) is somewhat delayed. MathWorkers are hard at work fixing problems in the pre-release beta. This delay was actually anticipated, as can be seen from the pre-release expiry date.
We should all be patient and let MathWorks fix these issues without pressure. This release could be a real home-run and MathWorks should do all it can to ensure that it works as transparently and as backward-compatible as possible so that it indeed becomes a home run rather than an outfield foul ball. Let’s not have a repeat of R2010b, which required two separate service-pack updates. I urge MathWorks to take their time – better safe than sorry. I urge everyone else to be patient – it’s worth the wait.
When 14b is finally out, I will be here with a planned series of articles explaining how we can make good use of all its new goodies. Start drooling…
Happy Jewish New Year everybody!
About 14b : it is definitely a major update. I already know that a lot of software here will not migrate into 14b. You were talking about 10b , for us the biggest gap was 11b to 12a (or any newer release) because TMW changed the behavior of matrix functions like setdiff, intersect, union, ismember … (fortunately we have the workaround LEGACY flag like -v6 !!)
I love new features but I hate compatibility issues
Maybe 14b will be alive in a few days before MATLAB Expo 2014 (2nd October @ Paris…and I will be there even if I am from south of France!!)
I agree concerning 14b, I prefer stability, functionability and compabilities support more than new functions.
@Aurélien> More updates of your blog would be welcomed 🙂
Dear Yair!
I’ve run into a problem using your findjobj utility, I am trying to build a GUI with several popup menus. I build a popup menu using hComboBox=uicontrol(‘Style’,’popup’,…), but for some reason the findjobj(hComboBox) returns an empty handle. When I do the same in the command window it works perfectly (also when I call: findjobj(‘class’,’MLComboBox’). Is there a reason why is it acting like that when I call the findjobj in a function?
And secondly, why is it that when I declare the same Position property to a Matlab popup menu, and an EditBox, the height of the 2 object differ?
I am using R2014b version.
Thanks, for your reply!
@Andras – perhaps the control is not yet visible by the time findjobj is called. Try calling drawnow; pause(0.05); and ensure you are not setting Visible=’off’.
Re the control height, this is how Matlab works internally; the height is automatic and cannot be controlled from Matlab. It is possible (but also not trivial) to do it in Java. You can search for this online.
Thanks, for the fast reply.
Sadly neither of those work, I still get an empty handle after calling findjobj.
I dont quite get your second answer, I thought the Position property sets [left bottom width height] the size of the object, but calling a simple JComboBox with javacomponent, or calling an MLComboBox with uicontrol, and then setting their position property to the exact same values, I still get 2 different height.
Alright, now I see, so the basic popup menu uicontrol height is not editable.
Correct. Try keeping the uicontrol height at its standard value (20px) – maybe that will help findobj() to find it. You don’t care about the height value anyway because as you have seen it does not really affect the actual displayed control height.
I try to build my GUI using normalized units to set the position property (to avoid setting the ResizeFcn). My main concern is that there is always a label, and sometimes an editbox also next to the popup, and I need to keep them in the same line, and height, etc … , for the GUI to look OK.