Matlab - GUI - 通过在另一个回调中更改变量来修改变量

Matlab - GUI - Modify a variable by changing it in an other callback

我想制作一个简单的程序,在按下 运行 按钮时循环显示递增的数字,并在循环中按下另一个按钮来更改该值。我想出的程序使用我到目前为止发现的增加数字并正确显示它,但我使用的变量显然彼此独立所以每当我将值重置为 0 时,循环会继续它之前离开的地方重置。

% --- 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

知道如何使这个测试变量成为全局变量、如何初始化它以及我应该将它放在文件中的什么位置吗?

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

围绕这个有几个选项!例如,您可以使用 handles 结构来传递 "global" 变量。在您的代码中,您必须像这样修改它:

% --- 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 结构的内容和全局变量的内容可以变为 "out of sync"。我被这个坑了两次,所以我不再用这个方法了。

第三种方法包含这样一个事实,即变量 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 时。

您可以将变量声明为全局变量。这样就可以了。

% --- 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

如果您的项目很小并且适合单个 M-file,您可以使用 nested functions 最轻松地解决这个问题。

如果您正在使用指南制作 GUI,那么您可以通过以下方式最轻松地完成此操作:(确保您先保存来自 GUI 编辑的 auto-generated m-file 的副本)

  1. 打开m-file
  2. 如果函数没有以关键字 end 结束,则将其添加到所有定义的函数中,除了第一个函数(其名称在 m-file 上)
  3. 在 m-file
  4. 的最底部添加一个额外的 end

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