2017-01-02 201 views
2

我想制作一个简单的程序,在按下运行按钮时在循环中显示递增的数字,并通过在循环中按下其他按钮来更改该值。我使用我发现的程序到目前为止增加了数量并正确显示,但我使用的变量显然是彼此独立的,所以无论何时将该值重置为0,循环都会继续之前留下的位置重置。Matlab - GUI - 通过在其他回调中修改变量来修改变量

% --- Executes on button press in stop. 
function stop_Callback(hObject, eventdata, handles) 
test = 0; 
set(handles.display, 'String', num2str(test)); 
guidata(hObject, handles); 

% --- Executes on button press in run. 
function run_Callback(hObject, eventdata, handles) 
test = 1; 
while test > 0 
    test = test + 1; 
    set(handles.display, 'String', num2str(test)); 
    guidata(hObject, handles); 
    pause(1); 
end 

任何想法如何使这项测试变量全球,如何初始化它,我应该把它放在文件中?

回答

1

是的,这是预期的行为!变量test的范围对每个函数都是局部的,所以您不能在一个函数中更改它,并期望更改后的值出现在另一个函数中。

这里有几个选项!例如,您可以使用handles结构传递“全局”变量。在代码中,你将不得不修改它,像这样:

% --- Executes on button press in stop. 
function stop_Callback(hObject, eventdata, handles) 
handles.test = 0; 
set(handles.display, 'String', num2str(handles.test)); 
guidata(hObject, handles); % Store the changed handles structure 

% --- Executes on button press in start. 
function run_Callback(hObject, eventdata, handles) 
handles.test = 1; 
while handles.test > 0 
    handles.test = handles.test + 1; 
    set(handles.display, 'String', num2str(handles.test)); 
    guidata(hObject, handles); % stores the changed handles structure 
    pause(1); 
    handles = guidata(hObject); % updates "handles" to see the change! 
end 

这是一个非常标准的方法,但它有一些缺点:这是超级容易不小心遗漏更新或检索handles结构。此外,由于这两个功能并行运行,它们容易受到竞争条件的影响。

第二种方法是使用global语句。它插入容易:

% --- Executes on button press in stop. 
function stop_Callback(hObject, eventdata, handles) 
global test; 
test = 0; 
set(handles.display, 'String', num2str(test)); 
guidata(hObject, handles); 

% --- Executes on button press in run. 
function run_Callback(hObject, eventdata, handles) 
global test; 
test = 1; 
while test > 0 
    test = test + 1; 
    set(handles.display, 'String', num2str(test)); 
    guidata(hObject, handles); 
    pause(1); 
end 

然而,这也带有一些缺点:现在变量test是真正的全球化。它可以在其他脚本,函数或GUI中进行更改,因此您应该选择比test更独特的名称,并且一般要小心。另外,如果(单例)GUI在不关闭的情况下重新启动,GUI的可视状态,handles结构的内容以及全局变量的内容可能会变得“不同步”。我被这两次咬伤,所以我不再使用这种方法。

第三种方法包含变量test应始终链接到GUI文本字段的事实。因此它使用display字段中的字符串替代变量。从本质上讲,这意味着使用getsetstr2doublenum2str很多:

% --- Executes on button press in stop. 
function stop_Callback(hObject, eventdata, handles) 
set(handles.display, 'String', num2str(0)); 
guidata(hObject, handles); 

% --- Executes on button press in start. 
function run_Callback(hObject, eventdata, handles) 
set(handles.display, 'String', num2str(1)); 
while str2double(get(handles.display, 'String')) > 0 
    set(handles.display, 'String', ... 
     num2str(str2double(get(handles.display, 'String')) + 1)); 
    guidata(hObject, handles); 
    pause(1); 
end 

这是冗长的,但它是我在这些情况下使用。这是最健壮的解决方案,尤其是在重新启动(单例)GUI时不首先关闭它。

+0

第一种方法按预期工作!我之前在测试中使用过它,但我没有意识到这一行“handles = guidata(hObject);%更新”句柄“以查看更改!”所以它不见了,所以它的行为就像我的请求中的代码。 谢谢! – user3548298

+0

关于第一种和第三种方法,最有效的是什么?我试图为音频制作一个实时处理程序,我需要小心这个问题 – user3548298

+0

我的直觉告诉我,两种方法都非常高效 - 带有'global'声明的方法可能是最快的。在第一种和第三种方法之间,我猜第一种方法更快。但只有测试才能确定。实时音频可能会非常棘手,您可能需要解决更先进的魔法。无论如何,祝你好运! –

0

您可以将变量声明为全局变量。这会做。

% --- Executes on button press in stop. 
function stop_Callback(hObject, eventdata, handles) 
global test; 
test = 0; 
set(handles.display, 'String', num2str(test)); 
guidata(hObject, handles); 

% --- Executes on button press in run. 
function run_Callback(hObject, eventdata, handles) 
global test; 
test = 1; 
while test > 0 
    test = test + 1; 
    set(handles.display, 'String', num2str(test)); 
    guidata(hObject, handles); 
    pause(1); 
end 
0

如果你的项目是小,适合单个M-文件,你可以很容易地通过使用nested functions解决这个问题。

如果您正在使用指南让您的GUI,那么你可以通过以下方式做到这一点最容易:(一定要保存副本首先从GUI编辑自动生成的M文件)

  1. 打开m文件
  2. 如果功能不与关键字end结束,然后将其添加到定义的所有功能,除了第一个函数(其名称是M-文件)
  3. 把额外end在你的m文件的最底部

之后,您在顶层函数中定义的任何变量都可用于较低层的函数(嵌套的函数,也是回调函数)。标准的Matlab编辑器将在此颜色之后以不同的方式突出显示变量,如果它们具有跨越许多功能的范围