A few days ago, a CSSM forum reader asked how to modify Matlab’s listbox scrollbars. Another user asked how to configure line-wrapping. I thought this is a good opportunity to describe how listbox and editbox scrollbars can be customized. The timing is particularly opportune, after I have recently described how the Matlab Editbox can be customized by accessing its underlying Java object using the FindJObj utility.
Both the listbox and the multi-line editbox uicontrols share a similar design: a multi-line Java control embedded within a JViewport within a JScrollPane (note that for historical reasons, the Java view-port class is called JViewport rather than the more standard camel-cased JViewPort). In addition to the view-port, the containing scroll-pane also contains two scrollbars (horizontal and vertical), as expected from standard Java scroll-panes.
Control of the scroll-pane’s scrollbar behavior is done via the JScrollPane’s VerticalScrollBarPolicy and HorizontalScrollBarPolicy properties.
VerticalScrollBarPolicy accepts the self-explanatory values of:
- VERTICAL_SCROLLBAR_ALWAYS (=22)
- VERTICAL_SCROLLBAR_NEVER (=21)
- and VERTICAL_SCROLLBAR_AS_NEEDED (=20)
- HORIZONTAL_SCROLLBAR_ALWAYS (=32)
- HORIZONTAL_SCROLLBAR_NEVER (=31)
- and HORIZONTAL_SCROLLBAR_AS_NEEDED (=30)
All these properties are static enumerated constants that can be referred using either their Java notation (e.g., JScrollPane.VERTICAL_SCROLLBAR_ALWAYS) or their equivalent numeric values. Using the non-numeric format is better, since it is more readable and the numeric values may change, but the choice is yours.
By default, Matlab implements a VerticalScrollBarPolicy of VERTICAL_SCROLLBAR_ALWAYS for sufficiently tall uicontrols (>20-25 pixels, which practically means always) and VERTICAL_SCROLLBAR_NEVER for shorter uicontrols.
For the horizontal scrollbar, Matlab implements a HorizontalScrollBarPolicy of HORIZONTAL_SCROLLBAR_NEVER for all editboxes and for narrow listboxes (<35 pixels), and HORIZONTAL_SCROLLBAR_AS_NEEDED for wide listboxes.
These settings are generally satisfactory. However, in some cases users may wish to modify the settings. For example, the default VerticalScrollBarPolicy setting of VERTICAL_SCROLLBAR_ALWAYS causes the vertical scrollbar to appear even when unneeded (the entire editbox content is visible). Also, we may wish to have a horizontal scrollbar on narrow listboxes and editboxes, something that the standard HORIZONTAL_SCROLLBAR_NEVER prevents. In both cases, a *_SCROLLBAR_AS_NEEDED policy might be more appropriate.
To modify these settings, we simply need to get the uicontrol’s underlying Java reference handle (using the FindJObj utility), and modify the appropriate property. For example:
% Create a multi-line (Max>1) editbox uicontrol hEditbox = uicontrol('style','edit', 'max',5, ...); % Get the Java scroll-pane container reference jScrollPane = findjobj(hEditbox); % Modify the scroll-pane's scrollbar policies % (note the equivalent alternative methods used below) set(jScrollPane,'VerticalScrollBarPolicy',20); % or: jScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED jScrollPane.setHorizontalScrollBarPolicy(30); % or: jScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
Note that updating the uicontrol handle (hEditbox)’s Position property has the side-effect of automatically reverting the scrollbar policies to their default values (HORIZONTAL_SCROLLBAR_NEVER and VERTICAL_SCROLLBAR_ALWAYS/NEVER). This also happens whenever the uicontrol is resized interactively (by resizing its container figure window, for example). It is therefore advisable to set jScrollPane’s ComponentResizedCallback property to “unrevert” the policies:
cbStr = sprintf('set(gcbo,''VerticalScrollBarPolicy'',%d)', ... jScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); hjScrollPane = handle(jScrollPane,'CallbackProperties'); set(hjScrollPane,'ComponentResizedCallback',cbStr);
By default, line-wrapping is turned on, effectively disabling horizontal scrolling (which is why Matlab set the HorizontalScrollBarPolicy to HORIZONTAL_SCROLLBAR_NEVER. However, in some cases it may be more useful to turn line-wrapping off and horizontal scrolling on using the TextArea’s setWrapping() method. Here’s a usage example:
jViewPort = jScrollPane.getViewport; jEditbox = jViewPort.getComponent(0); jEditbox.setWrapping(false); % do *NOT* use set(...)!!! newPolicy = jScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED; set(jScrollPane,'HorizontalScrollBarPolicy',newPolicy);
- setWrapping() only works for the default EditorKit, and fails for HTMLEditorKit – This is due to HTML’s inherent wrapping behavior, as can easily be seen in any browser webpage.
- while setWrapping() may seem like a regular setter method for a Wrapping property, in reality it is not. Actually, set(jEditbox,’wrapping’,flag) may crash Matlab. So, always use the setWrapping(flag) method variant, which is entirely safe.