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);
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
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'); % a schema.prop object hListener = handle.listener(hhSlider,hProp,'PropertyPostSet',@myCbFcn);
In addition to ‘PropertyPostSet’, we could also listen on ‘PropertyPreSet’, which is triggered immediately before the property is modified. There are also corresponding ‘*Get’ options. In relatively old Matlab releases (I believe R2007b and earlier, but I’m not certain), the option names were simply ‘PostSet’, ‘PreSet’ etc., without the ‘Property’ prefix.
Do you know of any other way to achieve continuous callbacks? If so, I would be delighted to hear in the comments section below.
Related posts:
- Inactive Control Tooltips & Event Chaining Inactive Matlab uicontrols cannot normally display their tooltips. This article shows how to do this with a combination of undocumented Matlab and Java hacks....
- Setting listbox mouse actions Matlab listbox uicontrol can be modified to detect mouse events for right-click context menus, dynamic tooltips etc....
- Uicontrol callbacks This post details undocumented callbacks exposed by the underlying Java object of Matlab uicontrols, that can be used to modify the control's behavior in a multitude of different events...
- The javacomponent function Matlab's built-in javacomponent function can be used to display Java components in Matlab application - this article details its usages and limitations...
- FindJObj GUI – display container hierarchy The FindJObj utility can be used to present a GUI that displays a Matlab container's internal Java components, properties and callbacks....
- UISplitPane UISplitPane was recently chosen as Matlab Central's Pick of the Week. Here I detail its use of some undocumented Matlab features....
Tags: callbacks, FindJObj, GUI, Java, listener, schema.prop, uicontrol, Undocumented feature
Categories: GUI, Java, Listeners, Medium risk of breaking in future versions, UI controls
This entry was posted
on Monday, February 8th, 2010 at 2:13 am PST
You can follow any responses to this entry through the RSS 2.0 feed.
You can leave a response, or trackback from your own site.

Hi,
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?
Dani
@Dani – Unfortunately, the window resizing event is only propagated upon mouse release. There’s probably a Java workaround, but I don’t know it. You can use the three separate methods shown above, but you’ll see the same result:
For the screensize issue try:
Not sure if there is some kind of listener for changes in that
The screensize can also be gotten via pure Matlab:
Note that if you have multiple concurrent monitors this gets a bit trickier.
You guys are worth gold! (German proverb, not sure it exists in English)
@Yair – thanks, good to know it cannot be done.
@Matt – excellent, works and detects changes in screen resolution.
@Yair – unfortunately
does not (reliably) return updated screen resolution info in cases where the resolution was changed during a running MATLAB session. However, now you got me worried regarding multiple monitors and I had a look at
which does seem to return correctly updated info.
To be precise, I didn’t say it cannot be done, only that I personally have not found a way to do it. I actually tend to think it can be done somehow.
Hi,
I recently implemented a GUI with AdjustmentValueChangedCallback for a JTree’s vertical slider. The acquired values were used to update the slider position of one or more dependent listboxes. (The tree shows a directory with all subdirectories and files, the listboxes only display one file type each, but in the same rows as they are in the tree.)
Problem is that if the JTree’s slider position changed fast (e.g. via mouse wheel usage), strings inside the listboxes are not in their correct positions or displayed twice.
The listbox strings are updated via “myExpFcn” and “myColFcn” and contain correct data.
“myAdjustFcn” gets myjslider’s “Maximum” and “Value” and sets them in mylb1slider and mylb2slider respectively. I noticed the callback is sometimes called twice (expand, collapse) or three times (mouse wheel) and does not update the listbox sliders correctly in the first run (seems to appear only within expand)…
Does anyone know of this display bug/problem/whatever?
Epic fail.
I tried all three methods, none worked for me. I am using a GUIDE created function, and to start with, I have the problem that I have no idea where the listeners should be created (openingFCN, main function or outside of function?). However, if I would be past that, at the next step, I don’t understand what input parameters are given when a function is referenced simply as @myCbFcn. I have gotten as far as getting this function executed (when moving it out into a separate file as opposed to having it in the main GUI file), but then I just get crap from schema.prop and Java gibberish instead of getting the handles through these calls. Sorry, I just don’t understand…
I’ll try to be more specific. In this example:
What input arguments are passed to @myCbFcn??? I thought it would be hObject, EventData, handles, but it really is not…
Thanks!
Janos
Trying to break it down a little more. Trying to put it into fnname_OpeningFcn, nothing happens on the slider movement event:
And updatetextbox looks like this in a separate file (i.e. once it registers a slide movement, execution should jump inside updatetextbox and give me keyboard access, so I can at least see what inputs it got – but it does not happen (probably because I defined the listener inside, at the OpeningFcn level?).
If I define the listener in the main function, then there is a problem – it runs through a lot of times. I can catch one where the figure is plotted already (where varargout already exists), grab the handle, add the listener… and nothing happens (sigh).:
In this case, I think as the whole namespace disappears once this instance of the function runs through, the listener disappears with it, too.
(I’ll post this now, and continue in the next)
So in the post above, I tried implementing handle.listener at the Opening_Fcn and the main function level. Last option is outside the function, at the command prompt level. And this is what I do…
Right, great news. So to do this, now I need a callback function of this form:
And this finally works!!
Phew. Now, on to the “interesting” question. How can I “package” this up into the GUI itself (which was, as said, created by GUIDE, so I can’t just put the listener line after the creation of a uicontrol object. Using a script, which launches the GUI, then contains the above commands in chronographical order?
In fact, question no. 2:
I chose GUIDE because the fact of not having to set uicontrol object positions and sizes by coding but graphically is very easy and fast for me. Was that silly, and is that the reason for all the above suffering? (i.e. once one needs something past very basic funtionality – e.g. continuous slider callback – GUIDE is NOT the way to go?
In case there WAS anyone who followed through my “troubleshooting”, thanks, any further advice for a noob like me highly welcome.
Cheers,
Janos
Last bit of info:
I based this on the function untitled.m (and the associated saved untitled.fig) from here:
http://www.mathworks.com/support/solutions/en/data/1-3SR0YI/index.html?product=ML&solution=1-3SR0YI
Which is supposed to be a solution for exactly this problem. On its own, it did not work, and that is when I tried implementing your solutions (though it is supposed to be what I am looking for, i.e. continuous slider callback from within a GUIDE-created GUI)
@Janos – hListener=handle.listener requires you to store the returned hListener handle somewhere – the listener only works as long as its handle is stored somewhere. A good place to store this listener is in the target object’s ApplicationData, using the built-in setappdata function:
You can do this in your main code – no need to use the Command Window. The reason it worked for you in the Command Window is that the handle.listener result was kept in the ans variable, so as long as ans was not changed the listener worked.
@Yair:
I see, makes sense! I put your 2 lines of code into my function’s OpeningFcn, the Callback function back at the bottom of the main GUI .m-file and it all works now, thanks! Sorry for polluting the thread with such a looooong entry!
Glad to help – that’s what I’m here for…
The most difficult questions sometimes have very simple solutions, as in this case
Thanks again, I even ended up using the “Donate” button. I don’t do that often, so you can be sure of seeing me here again!
Much obliged, Janos
Positive feedback such as yours is very important for me when I have to explain to my family why I spend so much time on this website, for no apparent benefit…
Hi,
I created a GUI using guide with two sliders to adjust image window and level. When I use setappdata to my slider object a new figure is created when I started to use the slider. My image is displayed in the new figure instead of my current GUI figure. Any idea why this is happening. Your help is appreciated. Thanks.
Cemil
@Cemil – this could be due to several reasons: My bet is that your figure has a hidden handle (HandleVisibility=’off’) and in your callback function you are using the gcf function or some other similar function that creates a new figure in such cases. Instead, use the actual figure handle that is available in your handles struct and ensure that you pass this handle to every function that could possibly need it (axes etc.).
Thank you very much Yair. That was a great help. I changed HandleVisibility of the figure from its default value ‘callback’ to ‘on’ and the problem is solved. I appreciate your help.
Best regards,
Cemil.