Customizing combobox popups

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)

MaximumRowCount=20 (default)

MaximumRowCount=20
(default)

MaximumRowCount=3

MaximumRowCount=3
 

MaximumRowCount=2

MaximumRowCount=2
 

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:

PopupWidthConstrained=false (default)

PopupWidthConstrained=false
(default)

PopupWidthConstrained=true

PopupWidthConstrained=true
 

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!

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

Tags: , , ,

Bookmark and SharePrint Print

8 Responses to Customizing combobox popups

  1. Aurélien says:

    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!!)

  2. oro77 says:

    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 :)

  3. Andras says:

    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.

    • Andras says:

      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.

    • Andras says:

      Alright, now I see, so the basic popup menu uicontrol height is not editable.

    • Yair Altman says:

      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.

    • Andras says:

      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.

Leave a Reply


Your email address will not be published. Required fields are marked *