Why doesn't assignin work in this context?

I have a matlab function which creates a variable named 'duration'.
function doStuff()
duration = 5;
Inside the function I create a uicontrol edit box to allow changing the duration value.
uicontrol(panel, 'Style', 'edit', 'Callback', {@setEditBoxNumber, 'duration', 0, 15});
The callback is a local function.
function setEditBoxNumber(obj, ~, ivar, min, max)
value = str2double(get(obj, 'String'));
if isnan(value)
if ~isempty(ivar)
value = evalin('base', ivar);
end
else
value = clip(value, min, max);
end
set(obj, 'String', num2str(value));
if ~isempty(ivar)
assignin('base', ivar, value);
end
value = evalin('base', 'duration');
value = duration;
end
The last two lines are used for debugging purposes. If duration is set to 4 and I type '2' into the text box the string is properly converted to the number 2. The value returned by the bottom evalin call is 2, but the value of duration is still 4.
This is very confusing. If I type letters in the text box the str2double call returns NaN and the upper evalin call properly retrieves the value for duration. I tried using the caller workspace but there was no change in behavior.

댓글 수: 1

Tom
Tom 2015년 8월 13일
I mistakenly said that setEditBoxNumber is a local function. It is a nested function, not a local function.

댓글을 달려면 로그인하십시오.

답변 (1개)

Walter Roberson
Walter Roberson 2015년 8월 12일

0 개 추천

When you use
value = evalin('base', 'duration');
value = duration;
the first line does not change duration in the current workspace, only in the base workspace. The line after that uses the duration of the current workspace, where it has not been changed. Remove the semicolon from the end of the
value = evalin('base', 'duration');
line to see the value as fetched from the base workspace.

댓글 수: 5

Tom
Tom 2015년 8월 13일
편집: Tom 2015년 8월 13일
The evalin call at the bottom of the callback function is for debugging purposes only. The call shows the assignin set the value for duration in some context, just not the context I want. When I look at the value of duration inside the context of the function doStuff I see that the value is unchanged. I've tried different combinations of 'base' and 'caller' and none do what I want, change the value of duration as seen within the function doStuff.
You have done the assignin('base') and that affects the variable named by ivar in the base workspace. To check it you can pull the value back,
value = evalin('base', ivar)
What is the relationship between doStuff and setEditBoxNumber ? If doStuff is not calling setEditBoxNumber directly and setEditBoxNumber is not a nested function of doStuff then setEditBoxNumber cannot force doStuff's variables to change.
Consider having a handles.ivars structure and having setEditBoxNumber change the value in handles.ivars.(ivar) and then guidata(hObject, handles) to push the value upward. Then at at any point that doStuff suspects that the value might be changed and wants to fetch the new value, doStuff should
handles = guidata(TheFigureNumber);
and pull the values out of handles.ivars.duration
Tom
Tom 2015년 8월 16일
setEditBoxNumber is a nested function inside of doStuff. It is not called directly. It is a callback function called by a uicontrol that is created by function doStuff. It appears that the callback workspace is not the same workspace used when the uicontrol is created.
I am thinking of using a structure which is passed as an argument to the callback. Something like the following:
function setEditBoxNumber(obj, ~, aStruct, fieldName, min, max)
Walter Roberson
Walter Roberson 2015년 8월 16일
편집: Walter Roberson 2015년 8월 16일
Callbacks are evaluated as if called from the base workspace. If the callback is defined as a nested routine then it can read and write variables in the nesting routine that are assigned values before the nested routine is defined.
function outer
a = 123;
function inner(src, event)
a = 456; %this changes outer's "a"
b = 789; %this changes a local variable "b"
end
b = -11111; %although this belongs to outer, it was not defined before inner() is defined so inner() does not have access to it
set(gcf, 'WindowButtonFcn', @inner)
end
Then the callback of inner() will change outer()'s value of "a", but outer() has already returned so outer() does not get to see the change. If you were to re-execute outer() then because it has the assignment to "a" it would change "a" back to 123. For this reason, functions that nest other functions often end up being "shells" that exist mostly to set something up, with all the real work being done by nested routines whose function handles get stored somewhere.

댓글을 달려면 로그인하십시오.

카테고리

도움말 센터File Exchange에서 Creating and Concatenating Matrices에 대해 자세히 알아보기

제품

질문:

Tom
2015년 8월 12일

편집:

2015년 8월 16일

Community Treasure Hunt

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

Start Hunting!

Translated by