(app designer) Callback for ROIMoved event does not work

Hi,
I have modified the Matlab app 'Image histogram example' with the possibility to draw an ROI and get the histogram of that part of the image. It works when I draws the ROI but when I moves the ROI I got the below error:
Warning: Error occurred while executing the listener callback
for event ROIMoved defined for class images.roi.Rectangle:
Undefined function 'allevents' for input arguments of type
'images.roi.Rectangle'.
> In images.roi.internal/ROI/stopDrag
In images.roi.internal.ROI
I have tried several alternatives from this forum but nothing works.
Below is a sceen shot from the code view with the relevant part visible.

 Respuesta aceptada

Tommy
Tommy el 17 de Abr. de 2020
Thomas,
When setting up the listener, use
addlistener(ROI, 'ROIMoved', @app.allevents)
Then, when defining allevents, use
function allevents(app, src, event)
...
end

7 comentarios

Thanks a LOT!
How did you know that and/or where can I read about this solution for the app designer? I have been reading help sections etc for several hours but did I miss it somewhere???
Thanks again and for a really quick answer.
/thomas
Tommy
Tommy el 17 de Abr. de 2020
Editada: Tommy el 15 de Mayo de 2020
Happy to help!
This is less about appdesigner and more about objects in general. appdesigner works (as far as I can tell) by defining a class for your app. All UI elements contained within your app (buttons, axes, etc) are set up as properties within that class, and methods (such as callbacks) are contained in the class as well.
When you run the app, you are creating an instance of the class. If you run the app two different times, you will create two different instances. If you click a button in one of the apps, that button's callback function is executed, but how does MATLAB know the instance in which it was called?
You may notice that many of your functions take app as the first argument. These functions are what MathWorks calls ordinary methods (instance or non-static methods elsewhere). Ordinary methods can only be called on instances of the app - a button's callback function is an ordinary method, because when you click that button, the function needs to know which instance to work with. Therefore, one argument of any ordinary method is always the instance they were called on. (It does not need to be called app - you can name it anything you want, like obj or this or self - but I guess appdesigner calls it app by default).
Now, ROIMoved callbacks need to take two arguments, the source and the event data. When you define allevents with
function allevents(app,evt)
you are basically saying, here is an ordinary method called allevents which takes one argument, evt (in addition to app, which it must take by virtue of being an ordinary method). You might rewrite the function definition to be
function allevents(src,evt)
but it doesn't matter. The first argument, src, will be treated as the instance of the class. It would be valid to call this function with either
allevents(app, myFirstArgument)
or
app.allevents(myFirstArgument)
as described in the page I linked above. However, if you attach this function as the ROIMoved callback, MATLAB will throw an error whenever it gets called, because it will be invoked with something like
app.allevents(someArgContainingTheSource, someOtherArgContainingTheEvent)
and with the way it is defined, it cannot take that many arguments. Consider something like this instead:
function allevents(app,src,evt)
This will work, because it takes the two required arguments in addition to the instance of the class.
Next, when you set up the listener with
addlistener(ROI, 'ROIMoved', @allevents)
MATLAB does not know what allevents is. If you set a breakpoint at that line, click your button, and enter debug mode, you can try to call allevents at the command window, but MATLAB will tell you it is undefined:
K>> allevents
Undefined function or variable 'allevents'.
You have to reference the method with app.allevents - again, without specifying the instance of the class, how is allevents supposed to know which particular app to work with? (Or, as described in the page I linked above, you could call it using allevents(app)). If you do supply app, the function will be found and called.
[However, you might still get an error if allevents uses input arguments which you don't supply. When you set app.allevents as the ROIMoved callback, MATLAB knows which arguments to supply, and it will supply both, which is why allevents needs to take two arguments (and taking us back to the previous paragraph). You could define allevents as
function allevents(app,src,evt)
disp('hi')
end
in which case you don't need to supply any arguments when calling it.]
Finally, note that
addlistener(ROI, 'ROIMoved', @(src,evt) allevents(app,src,evt));
and
addlistener(ROI, 'ROIMoved', @(src,evt) app.allevents(src,evt));
are also acceptable ways to connect allevents to 'ROIMoved'. Here, the callback is specified as an anonymous function which then calls allevents.
Hopefully this was not too hard to follow. Please do let me know if anything isn't clear!
(edit) Oh, and I knew this because I've been building my own user interface in MATLAB using a class. See here for an example. You can do what appdesigner does on your own, as long as you create everything programmatically!
A really good answer. Thanks!
Tolga
Tolga el 10 de Dic. de 2020
Editada: Tolga el 11 de Dic. de 2020
Hi,
I tried to write a very similar program by following your answer but I get an error:
Warning: Error occurred while executing the listener callback for event ROIMoved defined for class
images.roi.Circle:
Unrecognized method, property, or field 'PreviousPosition' for class
'images.roi.CircleMovingEventData'.
I am posting my addevent function and addlistener
Although my final goal is to update my binary mask when roi is moved, I tried to recreate what you have shown for starter. I am using version 2020b.
I would be very happy if you can give me some insight on what went wrong
Tolga
Tolga el 11 de Dic. de 2020
Editada: Tolga el 14 de Dic. de 2020
I found my problem. I think at some point they changed the names for images.roi.CircleMovingEventData class. I updated my code to run with the current names:
previousCenter = evtData.PreviousCenter;
currentCenter = evtData.CurrentCenter;
and everything worked fine. If you have same problem you can find new names of variables from https://www.mathworks.com/help/images/ref/images.roi.circlemovingeventdata-class.html
up vote for a thorough answer. salute
THank you very much!! Retainign the (src,evt) is also important indeed.

Iniciar sesión para comentar.

Más respuestas (1)

Heather Wannarka
Heather Wannarka el 8 de Jul. de 2021
This thread is incredibly helpful! It works beautifully in an app created in App Designer 2021a. I am now trying to implement an identical design in an older GUIDE interface and am getting an error similar to the original poster.
Error using images.roi.Rectangle/addlistener
Event 'addNewPositionCallback' is not defined for class 'images.roi.Rectangle'.
Error in RCSTool>DrawShape_Callback (line 757)
addlistener(H, 'addNewPositionCallback', @app.allevents)
Does GUIDE require a different class setup? I have been digging through forums and can find no better explaination than this one and I don't see any reason why it should not work. Any thoughts would be deeply appreciated.

Categorías

Más información sobre Develop Apps Using App Designer en Centro de ayuda y File Exchange.

Preguntada:

el 17 de Abr. de 2020

Comentada:

el 29 de Mayo de 2023

Community Treasure Hunt

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

Start Hunting!

Translated by