How to update guidata in the addlistener callback function?

I am developing a program for a company.
In the GUI I first grouped a number of checkboxes into one handle object (for instance I have 10 checkboxes).
for i = 1 : 10
checkboxes(i-1) = handles.(sprintf('checkbox%d', i));
end
handles.checkboxes= checkboxes;
Then I used the addlistener function to detect any changes for the group of checkboxes.
addlistener(handles.checkboxes, 'Value', 'PostSet', @(hObject, eventdata, handles) callback(hObject, eventdata, handles));
In the callback function, I wanted to update the value for 'anyObject' and in the end of the function I updated the handles structure so that the value of the 'anyObject' can be used by other functions.
function handles = callback(hObject, eventdata, handles)
handles.anyObject = get(handles.checkbox1,'Value');
% Update handles structure
guidata(hObject, handles);
The problem I have is that the program always throws me this error whenever I click the checkbox button:
Warning: Error executing listener callback for PostSet event on Value dynamic property in object of
matlab.ui.control.UIControl class:
Not enough input arguments.

 Respuesta aceptada

Note:
for i = 1:10
checkbox(i-1) = ...
will error on the first iteration, since checkbox(1-1=0) is not a valid index.
Note 2:
@(hObject, eventdata, handles) callback(hObject, eventdata, handles)
Since this anonymous function only job is to pass all its inputs to another function unchanged, it could just be skipped. That is
@callback
would do the same.
Note 3:
function handle = callback(...)
A proper callback never returns anything since there is no mechanism for getting that return value.
Now for your question, the immediate problem comes from the anonymous function you've defined. An listener callback must have two inputs arguments and only two. These are, the object generating the event, and some event data. Therefore, the inputs to your anonymous function can only be:
@(hobject, eventdata) ...
handles cannot be an input since it won't be sent by the event. Now, if you wanted handles to be passed to your callback function, you could define your anonymous function as:
@(hobject, eventdata) callback(hobject, eventdata, handle)
This would work with you example, but I wouldn't recommend that. The anonymous function captures the content of the handle structure at the point it is defined, so any change to that handle structure after that line won't be seen by your callback, e.g.:
lh = addlistener(handles.checkboxes, 'Value', 'PostSet', @(hObject, eventdata) callback(hObject, eventdata, handles));
handles.text = uicontrol('Style', 'text', 'String', 'some new control'); %add a new control to handle
The handle received by your callback will not contain the text field as it was created after handle was captured.
A safer way is simply to get the handle structure with guidata inside your callback, so:
lh = addlistener(handles.checkboxes, 'Value', 'PostSet', @callback); %not passing handle to callback
function callback(hObject, eventdata) %not receiving handle
handle = guidata(hobject); %get handle inside the callback.
%...

11 comentarios

Hi Guillaume,
Thanks so much for your swift reply.
I have made an update to the mistakes but I still received this error message:
Warning: Error executing listener callback for PostSet event on Value dynamic property in object of
matlab.ui.control.UIControl class:
Not enough input arguments.
Is there any way to update the handles inside the callback function?
Adam
Adam el 21 de Mzo. de 2017
What is the exact code you now have for the function signature and the addlistener line?
for i = 1:10
checkboxes(i) = handles.(sprintf('checkbox%d', i));
end
handles.checkboxes= checkboxes;
addlistener(handles.checkboxes, 'Value', 'PostSet', @callback);
%=============================================================
function callback(hObject, eventdata)
handles = guidata(hObject);
handles.text = 'testing';
guidata(hObject,handles);
return
After that the below error message is thrown:
Warning: Error executing listener callback for PostSet event on Value dynamic property in object of
matlab.ui.control.UIControl class:
Error using guidata (line 87)
H must be the handle to a figure or figure descendent.
Error in GUI>callback (line 189)
handle = guidata(hObject);
Ah ok, well that is a different error message to the one you previously reported which seemed more odd.
If you put a breakpoint on that line what is
hObject
?
Sorry... on which line?
The line giving the error:
handles = guidata( object );
The error remains the same:
Warning: Error executing listener callback for PostSet event on Value dynamic property in object of
matlab.ui.control.UIControl class:
Error using guidata (line 87)
H must be the handle to a figure or figure descendent.
Error in GUI>callback (line 189)
handle = guidata(hObject);
Well, of course, nothing changed, I'm asking what hObject is when you put a breakpoint on that line and you then type
hObject
on the command line.
Right, that particular problem is due to the fact that you're listening to a PostSet event on the Value of a UIControl. That's not really the normal way to get informed of changes to UIControl.
The proper way to do this, is to give a callback function to the Callback property of the UIControl. So instead of your addlistener, you'd have:
[handles.checkboxes.CallBack] = deal(@callback);
%or assign the Callback property in a loop to avoid the strange bracket syntax and the deal
And the callback would be, as previously shown:
function callback(hObject, eventdata)
%hobject is the UIControl triggering the event
handle = guidata(hobject); %get handle inside the callback.
%...
You can still do it with a PropSet listener, however, the object generating the event is a GraphicsMetaProperty object that you cannot pass to guidata. You actually get the Control in one of the event property, so if you want to do it with the listener the code has to be:
lh = addlistener(handles.checkboxes, 'Value', 'PostSet', @callback); %same as before
function callback(~, eventdata) %don't care about the source, it's not useful
handle = guidata(eventdata.AffectedObject)
%...
To reply @Adam: Sorry for the misunderstanding. After I type hObject the console printed out this:
hObject =
GraphicsMetaProperty with properties:
Name: 'Value'
Description: 'Value PropInfo'
DetailedDescription: ''
GetAccess: 'public'
SetAccess: 'public'
Dependent: 1
Constant: 0
Abstract: 0
Transient: 0
Hidden: 0
GetObservable: 1
SetObservable: 1
AbortSet: 1
NonCopyable: 0
GetMethod: []
SetMethod: []
HasDefault: 0
DefiningClass: [1×1 matlab.graphics.internal.GraphicsMetaClass]
To reply @Guillaume: Thanks so much for your help! It works like a charm!

Iniciar sesión para comentar.

Más respuestas (0)

Categorías

Más información sobre Interactive Control and Callbacks en Centro de ayuda y File Exchange.

Productos

Preguntada:

el 21 de Mzo. de 2017

Comentada:

el 22 de Mzo. de 2017

Community Treasure Hunt

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

Start Hunting!

Translated by