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.

 採用された回答

Guillaume
Guillaume 2017 年 3 月 21 日

1 投票

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 件のコメント

Woen Yon Lai
Woen Yon Lai 2017 年 3 月 21 日
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 2017 年 3 月 21 日
What is the exact code you now have for the function signature and the addlistener line?
Woen Yon Lai
Woen Yon Lai 2017 年 3 月 21 日
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);
Adam
Adam 2017 年 3 月 21 日
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
?
Woen Yon Lai
Woen Yon Lai 2017 年 3 月 21 日
Sorry... on which line?
Adam
Adam 2017 年 3 月 21 日
The line giving the error:
handles = guidata( object );
Woen Yon Lai
Woen Yon Lai 2017 年 3 月 21 日
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);
Adam
Adam 2017 年 3 月 21 日
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.
Guillaume
Guillaume 2017 年 3 月 21 日
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)
%...
Woen Yon Lai
Woen Yon Lai 2017 年 3 月 22 日
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]
Woen Yon Lai
Woen Yon Lai 2017 年 3 月 22 日
To reply @Guillaume: Thanks so much for your help! It works like a charm!

サインインしてコメントする。

その他の回答 (0 件)

カテゴリ

ヘルプ センター および File ExchangeCreating, Deleting, and Querying Graphics Objects についてさらに検索

製品

Community Treasure Hunt

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

Start Hunting!

Translated by