Clear Filters
Clear Filters

queue addlistener events or place event on EDT

6 views (last 30 days)
Every time the xlim changes I want to run some code.
L = addlistener(gca, 'XLim', 'PostSet', @my_callback);
If I use a listener, I seem to miss events if the callback is still running.
Thus I would like to queue property change event callbacks. Is this possible?
Alternatively, is it possible to have the callback queue a function on the EDT (event-dispatch thread) so that any changes are not missed?
The only really ugly solution I can come up with involves using the 'PropertyChangeCallback' of a java class since it seems to respond to being set in Matlab, as opposed to uicontrols which don't throw callbacks (I think) when changing their values via Matlab.
It appears that this is dependent on the callback code.
I had something like this:
t = tic;
If you do something like a horizontal zoom 2 - 3 times (quickly enough), only the first listener callback will run, even though you've changed xlim multiple times.
However if instead the code is:
t = tic;
r = rand(1,1e8);
Then rendering will not occur until the code has finished executing. Here I am using the rand() command to cause a reasonable delay (on my laptop 1.5s)
So in other words the blocking behavior of listeners depends on the callback code.
The missed events also only occur with user input. When running code the events run sequentially. For example, try this with the 'pause' version of the callback. In my case I get three events, rather than just 1.
set(gca,'xlim',[0 10]);
set(gca,'xlim',[0 20]);
set(gca,'xlim',[0 30]);
Jim Hokanson
Jim Hokanson on 27 Nov 2017
I tried the following and it only registers the first event, not subsequent ones:
ax = gca;
L = addlistener(gca, 'XLim', 'PostSet', @my_callback);
%Inside my_callback
t = tic;
Jim Hokanson
Jim Hokanson on 9 Jan 2018
Edited: Jim Hokanson on 15 Jan 2018
Just to follow up on this before I submit for technical support since I'm not getting the performance that I want. I want the following behavior:
1) Ensure that a function has always run after the xlim property changes. I don't need it to execute following every change, but if some time has passed with no change (a few hundred milliseconds), I want my function to have run after the change. More specifically, I can't miss a terminal event because of the function running.
2) It should not block other code execution for long periods of time. One approach to getting the last change is to check the xlim property as the function is about to terminate. If the property has changed, the function could run again. However, this could go on for a while and it should persistently block execution of other code, which is not desirable.
3) Indications of some rendering should be nearly immediate, even if the final processing is delayed.

Sign in to comment.

Accepted Answer

Jim Hokanson
Jim Hokanson on 5 Feb 2018
I found a different solution which appears to work nicely:
I don't understand the blog post details but below is what I am using based on the callbackOnEDTQueue() function referenced at the end of the post.
so now in initialize:
obj.L3 = addlistener(axes_handle.XRuler,'MarkedClean',@(~,~)obj.xrulerMarkedClean);
obj.callback_obj = handle(com.mathworks.jmi.Callback,'callbackProperties');
if isequal(obj.last_processed_xlim,get(obj.axes_handle,'XLim'))
%Some logging not shown, but the main call is:

More Answers (1)

Jim Hokanson
Jim Hokanson on 26 Nov 2017
Edited: Jim Hokanson on 27 Nov 2017
Here's one (ugly) solution.
This setup function does the following:
  1. Sets up listeners that I care about.
  2. Attaches a Java button to a figure which I've hidden ('Visible','off','HandleVisibility','off')
  3. Sets up the actual callback that I want on the Java button
function initialize(obj,axes_handle)
[obj.j_comp, temp] = javacomponent('javax.swing.JButton',[],obj.fig_handle);
obj.h_container = handle(temp);
obj.axes_handle = axes_handle;
if verLessThan('matlab', '8.4')
size_cb = {'Position', 'PostSet'};
size_cb = {'SizeChanged'};
obj.L1 = addlistener(axes_handle,'XLim','PostSet', @(~,~)obj.listenerCallback);
obj.L2 = addlistener(axes_handle, size_cb{:}, @(~,~) obj.listenerCallback);
The listener code is as follows. By toggling the text we generate the callbacks of interest on the EDT.
function listenerCallback(obj)
%Note the try statement because j_comp gets deleted asynchronously
%fprintf('1 %s\n',mat2str(get(obj.axes_handle,'xlim')));
if obj.last_string_index == 1
obj.last_string_index = 2;
obj.last_string_index = 1;
%fprintf('2 %s\n',mat2str(get(obj.axes_handle,'xlim')));


Find more on Interactive Control and Callbacks in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!