Every few months, a CSSM forum reader asks how to set up a continuously-invoked slider callback: Matlab’s slider uicontrol invokes the user callback only when the mouse button is released, and not continuously while the slider’s thumb is dragged. This functionality was again referred-to yesterday, and I decided it merits a dedicated post.
There are three distinct simple ways to achieve continuous callbacks:
Using Java callbacks
As explained in an earlier article, Matlab uicontrols are basically Java Swing objects that possess a large number of useful callbacks. Matlab sliders’ underlying Java objects, which are really not JSliders but JScrollBars, have an AdjustmentValueChangedCallback property that is useful for our purposes and is accessible using the FindJObj utility. Simply download FindJObj from the File Exchange, and then:
hSlider = uicontrol('style','slider', ...); jScrollBar = findjobj(hSlider); jScrollBar.AdjustmentValueChangedCallback = @myCbFcn; % or: set(jScrollBar,'AdjustmentValueChangedCallback',@myCbFcn)
Where myCbFcn is the Matlab callback function that will be invoked continuously when the arrow buttons are depressed or the slider’s thumb is dragged.
Using an event listener
An alternative to the Java route is to use Matlab’s undocumented handle.listener function to listen to the slider’s Action event, as follows:
hListener = handle.listener(hSlider,'ActionEvent',@myCbFcn); setappdata(hSlider,'sliderListener',hListener); % this is important - read below
This alternative is used by Matlab’s own imscrollpanel function:
if isJavaFigure % Must use these ActionEvents to get continuous events fired as slider % thumb is dragged. Regular callbacks on sliders give only one event % when the thumb is released. hSliderHorListener = handle.listener(hSliderHor,... 'ActionEvent',@scrollHorizontal); hSliderVerListener = handle.listener(hSliderVer,... 'ActionEvent',@scrollVertical); setappdata(hScrollpanel,'sliderListeners',... [hSliderHorListener hSliderVerListener]); else % Unfortunately, the event route is only available with Java Figures, % so platforms without Java Figure support get discrete events only % when the mouse is released from dragging the slider thumb. set(hSliderHor,'callback',@scrollHorizontal) set(hSliderVer,'callback',@scrollVertical) end
In this case,
hScrollpanel is merely a handle to a panel in Matlab’s imscrollpanel code. You can use any Matlab control to store the listener handle, including
hSlider itself, which would be simplest. It doesn’t matter where or how exactly you store
hListener, since you will not use it directly in your program. The important thing is just to store it *anywhere*, so that it remains in persistent (heap) memory. As long as the reference handle is “alive”, the listener will keep working. This is explained here.
Addedndum 2014-08-20: In R2014a the event name has changed from ActionEvent to ContinuousValueChange. Also, handle.listener will not work in the upcoming HG2. Therefore, it would be best to use the following code snippet instead:
try % R2013b and older addlistener(hSlider,'ActionEvent',@myCallbackFcn); catch % R2014a and newer addlistener(hSlider,'ContinuousValueChange',@myCallbackFcn); end
Using a property listener
The handle.listener function can also be used to listen to property value changes. In our case, set a post-set listener, that gets triggered immediately following Value property updates, as follows:
hhSlider = handle(hSlider); hProp = findprop(hhSlider,'Value'); try % R2014b and newer % hProp is a matlab.graphics.internal.GraphicsMetaProperty object addlistener(hSlider,hProp,'PostSet',@myCbFcn); catch % R2014a and older % hProp is a schema.prop object hListener = handle.listener(hhSlider,hProp,'PropertyPostSet',@myCbFcn); setappdata(hSlider,'sliderListener',hListener); % this is important - read above end
In addition to ‘PostSet’, we could also listen on ‘PreSet’, which is triggered immediately before the property is modified. There are also corresponding ‘*Get’ options.
Do you know of any other way to achieve continuous callbacks? If so, I would be delighted to hear in the comments section below.
another functionality that would benefit from continuous callback is figure resizing. For example, it would be useful to allow for figure resizing, but only to a certain minimum size. Since ResizeFcn callback is only evaluated once the mouse button is released, ‘jumping’ from, for example, very small resized windows to the desired minimum size cannot be avoided.
The other problem with figure sizes and resizing is that Matlab only knows the original screen size. This leads problems if the screen resolution has been changed on the way, for example due to connection to a projector.
Can these be solved with some java magic?