从侦听器调用时,Matlab guidata(hObject,handles)未更新 UI 中的标志

Matlab guidata(hObject, handles) not updating flag in UI when called from listener

这是许多其他人遇到的类似问题,其中 guidata(hOjbect, handles) 似乎没有更新值。我正在将它与侦听器一起使用,但不确定如何进行。

在我的 gui_OpeningFcn 中有以下行:

addlistener(handles.s, 'name', 'PostSet', @(s,e)updatefilesave(hObject, [], handles));

这会适当地设置侦听器,并且会在修改名称时调用 updatefilesave。然而,updatefilesave里面是下面的代码:

handles.fileUnsaved = true;
guidata(hObject, handles);

在函数内部,两条线都有效。当我在第一行和步骤上设置断点时,fileUnsaved 设置为 true。在我执行第二行之后(仍在 updatefilesave 函数内),handles.fileUnsaved 仍设置为 true。

但是,当我退出该函数时,绿色箭头会出现在 gui_OpeningFcn 函数的 addlistener 行上。在此级别,handles.fileUnsaved 现在设置回 false。

如何在使用侦听器时获取要更新的句柄?

编辑

我想做的是知道输入字段何时更改,以便我可以提示用户在关闭程序之前保存他们的工作。我检查了 CloseRequestFcn 中的 fileUnsaved 标志,如果为真,我会在退出前询问用户是否要保存。

function namebox_Callback(hObject, eventdata, handles)

newName = handles.namebox.String;
if ~isempty(newName)
    handles.s.name = newName; % (listener gets triggered here post set)
end

handles.namebox.String = handles.s.name;

guidata(hObject, handles); % (namebox's local handles with fileUnsaved set to false gets put into hObject)

这就是为什么我不能在 CloseRequestFcn 中调用 handles = guidata(hObject) 的原因。阻止这种情况的唯一方法是在我调用 guidata(hObject, handles) 之前在名称框回调中调用 handles = guidata(hObject)。但是在任何地方都这样做会破坏使用听众的意义。我会在每个回调函数(大约 50 个)中将 fileUnsaved 设置为 true。

一般来说,如果您希望从一个回调中调用一个函数来修改 handles,然后让调用函数可以使用这些更改,您不仅需要保存handles 被调用函数中的结构(以便它们可用于其他回调),但你必须 re-load 调用函数中的 handles 结构,否则调用函数将只是使用它自己的 handles 本地(和未修改)副本,因为它无法知道它已被修改。

function main_callback(hObject, eventData, handles)

    % Set the value to one thing
    handles.value = false;

    sub_callback(hObject, eventData, handles);

    % Check that the value is STILL false
    disp(handles.value)

    % Load in the change so that handles gets updated
    handles = guidata(hObject);

end

function sub_callback(hObject, eventData, handles)
    handles.value = true;

    % Save the value
    guidata(hObject, handles);
end

另一种选择,是让你的其他功能实际上 return 修改后的 handles

function handles = sub_callback(hObject, eventData, handles)
    handles.value = true;

    guidata(hObject, value);
end

然后在调用函数中,您可以使用输出参数覆盖本地 handles 变量

handles = sub_callback(hObject, eventData, handles);

现在回答你关于 addlistener 的具体问题,因为回调是在 "asynchronous" 意义上执行的,return 一个值实际上没有意义。不过,我建议的是重新加载 handles 数据(如第一个示例所示),然后再次使用 handles(您希望它被更改的地方)以确保您拥有大多数 up-to-date 版本。

我偶然发现这个线程也有类似的问题,但对我来说修改监听器内部的句柄似乎有效。

在外部函数中,我有这样的东西:

handles.myListener = addlistener(ObjectThrowingEvent,'EventName', @(src,evt)ListenerFunction(src, evnt, hObject));
guidata(hObject,handles);

然后在函数里面

function ListenerFunction(ObjectThrowingEvent, eventData, hObject)
  handles = guidata(hObject)
  % a bunch of stuff happens, including updates to the handles structure
  guidata(hObject, handles);

对我来说,不同之处在于我传入 hObject 并在侦听器中查找来自 hObject 的句柄。即使侦听器是异步的,它也会被传递给 hObject,我认为它只是指向图形的当前状态,而不是一些本地未更新的副本。

我很好奇这是否适合您。到目前为止,它似乎在我的代码中有效。