【问题标题】:How can you Interupt a function from a GUI callback without adding an interupt-check to the function? (MATLAB)如何在不向函数添加中断检查的情况下从 GUI 回调中中断函数? (MATLAB)
【发布时间】:2011-09-22 17:38:29
【问题描述】:

所以,我有一个基本上允许用户迭代处理数据的 GUI。因此,有一个开始/停止按钮和一个显示数据当前状态的显示器。当点击开始按钮时,回调函数调用如下所示的数据处理函数:

function result = process_data(data)
    result = 0;
    for big_loop=big_start:big_end
        for small_loop=small_start:small_end
            result = result+data; %in reality just some fancier matrix ops
        end
    end

我的问题是如何实现停止按钮的回调,以便在小循环的当前迭代之后从 process_data 返回。

现在我通过将 process_data 代码修改如下来做到这一点:

    function result = process_data_new(data)
        result = 0;
        for big_loop=big_start:big_end
            for small_loop=small_start:small_end
                result = result+data; %in reality just some fancier matrix ops
%new code start -----------------
                if interrupt_flag
                    return;
                end
%new code end -------------------- 
            end
        end

但是,我真的希望从 GUI 端处理中断,这样我的代码就不会被中断检查乱七八糟(我的真实代码会经常非常涉及这种事情,并且用户有时需要更改 process_data 函数)。

这可能吗?我想这将涉及使所有循环变量成为“可观察”属性,然后等待 small_loop 更改,但我无法弄清楚如何实现回调的细节。

【问题讨论】:

  • 这是我想到的解决方案的充实版本:使 small_loop 成为一个可观察的属性,然后为它创建一个处理程序(每当值更改时调用)。这个处理程序只会寻找interrupt_flag,如果为真,那么它将杀死/返回process_data函数。最后一点是我不确定的部分......
  • 另外,部分解决方案是让按下停止导致计算挂起,直到再次按下开始按钮。

标签: user-interface matlab callback control-flow


【解决方案1】:

这可能会有所帮助:

有一个按钮“停止”,在它的回调中,设置一个标志为真。

在较小的循环中(即另一个忙于循环中的回调),它将在其(小)循环的顶部(或底部)检查此标志。

如果标志设置为真,它会立即使其为假并终止整个循环并返回。 (在循环中添加检查以检查是否设置了此标志)

因此,如果点击发生在最后一次检查之后,用户在点击 STOP 后最多需要等待一个较小的迭代来完成。

回调会互相打断,所以上面的方法有效。

标志在 userData 缓冲区中设置,并且每次都由另一个回调从那里读取。

我的一个例子中的这个 sn-ps 代码

小循环示例

 function status= output(t,x,~,data)
         %called by ode45 after each step. Plot the current
         %pendulum position for simulation

         userData = get(data.handles.figure1, 'UserData');
         if userData.stop
             status=true;
             g_status =true;
         else
             status = false;
             .... do real work
         end
     end

“运行”按钮回调

% --- Executes on button press in run_btn.
function run_btn_Callback(hObject, eventdata, handles)
% hObject    handle to run_btn (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

[data,status] = parse_input(handles);
if not(status)
     return;
end
.....
userData.stop = false;
set(handles.figure1, 'UserData',userData);
...

停止按钮回调

% --- Executes on button press in reset_tag.
function reset_tag_Callback(hObject, eventdata, handles)
% hObject    handle to reset_tag (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


data = get(handles.figure1, 'UserData');
data.stop = true;
set(handles.figure1, 'UserData',data);
.....

【讨论】:

  • 哇,感谢您的帮助。我会尝试一下,然后告诉你它是如何工作的
  • 嗯,不幸的是,这似乎是对我在问题中提到的“解决方案”的详细说明。它应该可以工作,但理想情况下我希望 process_data 函数中没有额外的代码。这可能吗?
  • 您只需在循环中添加一个额外的检查。我不知道如何通过不添加代码来做到这一点。我不会魔法:)
【解决方案2】:

如果你有并行计算工具箱,那么你可以创建一个Task。

否则,我认为不添加您建议的控制流是不可能的,因为没有其他方法可以创建处理线程并从您的 UI 中停止它。

【讨论】:

  • 我认为您不需要并行计算工具箱,因为 GUI 回调函数在触发时已经从其他处理中拦截控制。其他人可以确认/否认这一点吗?
  • 如果没有 PCT,您将无法控制计算线程。 GUI 回调确实会中断处理,但您不能以编程方式停止刚刚中断的线程。即使你抛出一个错误,它也会终止回调并恢复它正在做的事情。
【解决方案3】:

您基本上想要的是在用户按下“停止”按钮后终止 process_data。不幸的是,这是不可能的,因为 matlab 中没有真正的线程。因此,您唯一的解决方案是您自己实施的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-07
    • 1970-01-01
    • 1970-01-01
    • 2012-07-12
    相关资源
    最近更新 更多