handles not being updated with guidata in callback

5 ビュー (過去 30 日間)
Callum Clarke
Callum Clarke 2016 年 5 月 17 日
コメント済み: Callum Clarke 2016 年 6 月 15 日
The following code creates a ruler (imdistline) and defines a callback function on position change, so I can have a label move as the ruler moves. Problem is the callback seems to lose the new handles, so every call to redraw the label doesn't find an existing label and draws another at the new position. Relevant code is as follows:
% --- Executes on button press in rulerPushButton.
function rulerPushButton_Callback(hObject, ~, handles)
% Create a ruler on the zoomAxes
% if ruler doesn't exist, create one
if ~isfield(handles.ruler, 'handle') % TODO check if this works for destroyed handle
handles.ruler.handle = imdistline(handles.zoomAxes);
handles.ruler.api = iptgetapi(handles.ruler.handle);
setColor(handles.ruler.api, [1 1 0]);
drawRulerLabels(hObject, handles);
% Constrain ruler to image boundaries
constrainToRectFcn = makeConstrainToRectFcn('imline', get(handles.zoomAxes, 'XLim'), get(handles.zoomAxes,'YLim'));
handles.ruler.api.setPositionConstraintFcn(constrainToRectFcn);
% Create callback for ruler movement
% Create anonymous function to pass as callback
% anonfnc = function handle name
% @ creates handle
% (x) input arguments
% followed by statement
anonCB = @(pos) rulerNewPos_Callback(hObject, handles, pos);
handles.ruler.api.addNewPositionCallback(anonCB);
guidata(hObject, handles);
end
end
% Executes on ruler movement. pos is 2-by-2 array [x1 y1; x2 y2]
function rulerNewPos_Callback(hObject, handles, ~)
handles = drawRulerLabels(hObject, handles);
guidata(hObject, handles); % Doesn't work
end
handles = drawRulerLabels(hObject, handles) does what it should and returns correct handles, but after guidata(hObject, handles) and returning from the function the handles are lost. I'm assuming it's because the passed hObject is incorrect but I'm not sure why that should be. You can probably tell by the comments I'm not too familiar with anonymous functions and I suspect the problem could be in there somewhere. Any help appreciated.

採用された回答

Geoff Hayes
Geoff Hayes 2016 年 5 月 17 日
Callum - I think that the problem is with how you define the anonymous function
anonCB = @(pos) rulerNewPos_Callback(hObject, handles, pos);
Whenever the function rulerNewPos_Callback is called, it will be with the inputs (except for pos) defined at the time it was assigned to anonCB. So this function will always be "receiving" an outdated version of handles.
What you can do instead is the following. Change your assignment to
anonCB = @(pos) rulerNewPos_Callback(hObject, handles.figure1, pos);
where figure1 is the handle to your figure/GUI (you may have named this differently). Then your function signature and body becomes
function rulerNewPos_Callback(hObject, hGui, ~)
handles = guidata(hGui); % get the updated handles object
handles = drawRulerLabels(hObject, handles);
guidata(hObject, handles); % or use hGui instead of hObject (doesn't matter)
end
So we just use the handle to the GUI to obtain its handles structure via guidata.
Try the above and see what happens!
  2 件のコメント
Callum Clarke
Callum Clarke 2016 年 5 月 18 日
編集済み: Callum Clarke 2016 年 5 月 18 日
Hi Geoff, thanks for taking the time to answer. I had similar suspicions so I checked the state of handles as the callback was called, and it was being passed an up to date handle and hObject. I'm not going to pretend to know how that works though as it really does look like the anon function if being passed fixed versions of the variables.
Anyway, during these tests I discovered that I'm an idiot and found the problem, I've put it in an answer.
Callum Clarke
Callum Clarke 2016 年 6 月 15 日
So, turns out you were correct too; going back to this code the problem reared its ugly head again and your solution worked. I've accepted your answer instead.

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

その他の回答 (1 件)

Callum Clarke
Callum Clarke 2016 年 5 月 18 日
The problem was actually that the first call to drawRulerLabels in rulerPushButton_Callback was updating the handles, but the code following it then used the unmodified version for further changes. This was fixed simply by returning the new handles variable. The function is now as follows.
% --- Executes on button press in rulerPushButton.
function rulerPushButton_Callback(hObject, ~, handles)
% Create a ruler on the zoomAxes
% CC: ideally write custom ruler that can have different ends (head/tail)
% and different label positions
% if ruler doesn't exist, create one
rulerExists = 0;
if isfield(handles.ruler, 'handle')
if isvalid(handles.ruler.handle)
rulerExists = 1;
end
end
if rulerExists
handles.ruler.handle = imdistline(handles.zoomAxes);
handles.ruler.api = iptgetapi(handles.ruler.handle);
setColor(handles.ruler.api, [1 1 0]);
handles = drawRulerLabels(hObject, handles); % Modifies handles so returns modified version
% Constrain ruler to image boundaries
constrainToRectFcn = makeConstrainToRectFcn('imline', get(handles.zoomAxes, 'XLim'), get(handles.zoomAxes,'YLim'));
handles.ruler.api.setPositionConstraintFcn(constrainToRectFcn);
% Create callback for ruler movement
% Create anonymous function to pass as callback
% anonfnc = function handle name
% @ creates handle
% (x) input arguments
% followed by statement
anonCB = @(pos) rulerNewPos_Callback(hObject, handles, pos);
handles.ruler.api.addNewPositionCallback(anonCB);
guidata(hObject, handles);
end
end

カテゴリ

Help Center および File ExchangeMigrate GUIDE Apps についてさらに検索

タグ

Community Treasure Hunt

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

Start Hunting!

Translated by