在MATLAB中的进程中停止GUI

问题描述:

我正在使用MATLAB R2014b中的GUIDE设计GUI。我的程序有一个长循环(需要2〜5小时处理)。我想在我的GUI中有一个按钮,用户每次都要停止该过程(GUI基于循环的结果不断更新图形和文本)。类似于在结束循环之后按Control+C。我怎样才能实现这个?在MATLAB中的进程中停止GUI

PS。 我不想让MATLAB删除我的工作区。用户可以通过更改GUI中的某些选项,使用先前加载的数据和工作空间来继续该过程。

+1

嗨,你是否尝试过下面的答案?他们是否为你工作? – 2015-02-23 17:58:51

+0

这两个答案都很好:-)。为什么我们不能选择接受的两个答案:-) – user2991243 2015-02-24 14:57:05

+0

哈哈我不知道:)但是你可以选择一个,这样线程将被关闭。谢谢! – 2015-02-24 14:58:58

下面是应该工作一招:在某处的GUI,就像其OpeningFcn例如,初始化一个名为例如StopNow标志false并将其存储在GUI的手柄结构。然后在需要很长时间执行的循环中,每当标志设置为true时,将if语句与return调用相关联。这将停止循环的执行,并且您将有权访问您的数据。您可以通过按钮来更改标志值。

示例代码:我做了一个简单的GUI,它开始枚举for循环中的数字并将它们打印在文本框中。当您按下STOP按钮时,该标志被设置为真,循环停止。如果有什么不清楚的,请告诉我。按STOP按钮后,

function StopGUI 

clear 
clc 
close all 

%// Create figure and uielements 
handles.fig = figure('Position',[440 500 400 150]); 

handles.CalcButton = uicontrol('Style','Pushbutton','Position',[60 70 80 40],'String','Calculate','Callback',@CalculateCallback); 

handles.StopButton = uicontrol('Style','Pushbutton','Position',[250 70 80 40],'String','STOP','Callback',@StopCallback); 

%// Initialize flag 
handles.StopNow = false; 

handles.Val1Text = uicontrol('Style','Text','Position',[150 100 60 20],'String','Value 1'); 
handles.Val1Edit = uicontrol('Style','Edit','Position',[150 70 60 20],'String',''); 



guidata(handles.fig,handles); %// Save handles structure of GUI. IMPORTANT 

    function CalculateCallback(~,~) 

     %// Retrieve elements from handles structure. 
     handles = guidata(handles.fig); 


     for k = 1:1000 

      if handles.StopNow == false 
       set(handles.Val1Edit,'String',num2str(k)); 
       pause(.5) %// The pause is just so we see the numbers changing in the text box. 

      else 
     msgbox('Process stopped'); 
       return 
      end 

     end 

     guidata(handles.fig,handles); %// Save handles structure of GUI. 
    end 

    function StopCallback(~,~) 

     %// Retrieve elements from handles structure. 
     handles = guidata(handles.fig); 

     handles.StopNow = true; 

     guidata(handles.fig,handles); %// Save handles structure of GUI. 
    end 

end 

截图:

enter image description here

希望帮助!

+0

这是工作,因为在['暂停](http://fr.mathworks.com/help/matlab/ref/pause.html)matlab继续处理HG回调。如果在处理循环中没有“暂停”或“drawnow”,GUI将会停止(单线程执行模型)。 – CitizenInsane 2015-02-07 16:47:54

+0

那么一个循环应该是完整的,之后我们可以停止这个过程?我们无法在循环工作中停止流程?谢谢。 – user2991243 2015-02-09 16:35:41

+0

是的,如果你愿意,你可以在中间停下来;尝试代码自己看:) – 2015-02-09 16:37:55

最佳的解决办法是使用独立的线程(一个用于用户界面和一个用于处理)也许使用并行工具箱。无论如何,这将是非常复杂的同步两个。

所以,这里是一个简单的解决方案,它仅依赖于anonymous功能(委派接口处理块外部刷新)drawnow功能(以迫使所述图形界面,以处理其消息)

示例应用程序

的示例应用程序一起工作是非常基本的。它包含:

  • 甲设置面板(仅与一个设置中,迭代的用于处理块的数目)
  • 进度条
  • 一个GO /取消按钮

NB:源代码很长(大约250行,主要是由于gui的创建),所以我放弃了它here

ResponsiveGuiInterface

创建GUI并不重要。最重要的部分是处理模块,匿名函数来检查代码和回调以响应GUI事件。因此,我将仅详细论述论文。

处理块

处理块是一个简单的常规:

function [] = processing(count, instrumentation) 
%[ 
    for ki = 1:count, 

     instrumentation.CheckCancel(); 
     instrumentation.Progress((ki-1)/count); 

     if (ki > 1), pause(1); end 

     instrumentation.CheckCancel(); 
     instrumentation.Progress(ki/count); 

    end 
%] 
end 

关于它的唯一特殊的是,它需要一个附加instrumentation结构。该结构具有两个字段,指向调用者定义的两个函数(即图形界面)。我们很快会看到如何。

  • CheckCancel负责,如果用户想要停止处理产生错误的功能。
  • Progress是委托进展报告的功能。

这里是匿名函数是如何连接到图形界面(见代码doProcessing子功能):

% Connect instrumentation callbacks with the gui 
instrumentation.CheckCancel = @(ratio)onCheckCancel(dlg); 
instrumentation.Progress = @(ratio)onProgress(dlg, ratio); 

% Perform the processing 
processing(settings.NumberOfIterations, instrumentation); 

进展和CheckCancel处理程序

下面是该处理程序由GUI定义为Progress

function [] = onProgress(dlg, ratio) 
%[ 
    % Update the progress bar value 
    data = guidata(dlg); 
    uiprogress(data.handles.pbProgress, ratio); 

    % Force interface to refresh 
    drawnow(); 
%] 
end 

这很简单,它只是更新进度条控件并强制GUI刷新(提醒说matlab是单线程的,目前正在执行处理块,因此我们需要强制GUI刷新)。

这里是CheckCancel处理程序:

function [] = onCheckCancel(dlg) 
%[ 
    % Force interface to process its events 
    drawnow(); 

    % Check 'UserData' has not been modified during events processing 
    guiState = get(dlg, 'UserData'); 
    if (~isempty(guiState) && .... 
     strcmp(guiState, 'CancelRequested') || strcmp(guiState, 'CloseRequested')) 
     error('System:OperationCanceledException', 'Operation canceled'); 
    end 
%] 
end 

再次,这是很简单的。我们强制GUI来处理事件(按钮点击等),然后我们读取UserData是否被修改为某个期望值。如果是这样,我们引发一个异常来停止处理。再次提醒当前正在执行的代码是处理块。

GUI事件处理程序

GUI仅有两个有趣的事件。用户点击关闭按钮,他/她点击开始/取消按钮。注意:即使matlab被锁定执行处理块,GUI事件仍然被处理,因为处理块不时地(通过检测代表的意思)调用drawnow

下面是关闭按钮的代码:

function [] = onCloseRequest(dlg) 
%[ 
    % If already in computation mode  
    if (~isempty(get(dlg, 'UserData'))) 
     % Just indicate close is requested and leave immediatly 
     set(dlg, 'UserData', 'CloseRequested'); 
     data = guidata(dlg); 
     set(data.handles.btnGoCancel, 'Enable', 'off', 'String', 'Cancelling...'); 
     return; 
    end 

    % Immediate close 
    delete(dlg); 
%] 
end 

这很简单,如果我们在运行模式下,我们只是信号,我们要停下来,否则我们立即关闭对话框。

这里是旅途中的代码/取消键:

function [] = onGoCancelClick(dlg) 
%[ 
    % If already in computation mode  
    if (~isempty(get(dlg, 'UserData'))) 
     % Just indicate cancel is requested and leave immediatly 
     set(dlg, 'UserData', 'CancelRequested'); 
     data = guidata(dlg); 
     set(data.handles.btnGoCancel, 'Enable', 'off', 'String', 'Cancelling...'); 
     return; 
    end 

    % Go into computation mode 
    [settings, err] = tryReadSettings(dlg); 
    if (~isempty(err)) 
     waitfor(msgbox(err.message, 'Invalid settings', 'Error', 'Modal')); 
    else 
     enterComputationMode(dlg); 
     err = doProcessing(dlg, settings); 
     leaveComputationMode(dlg, err); 
    end 
%] 
end 

这是长一点,总之这是一样的。如果我们处于跑步模式,我们只是表示我们想停止;否则,界面处于正常模式,我们开始处理。

功能tryReadSettingsenterComputationModeleaveComputationMode只是胶以更新控制在界面和漂亮报告错误或取消。

结论

我们设计了一个响应的图形界面仅依靠drawnowanonymous功能。这当然只是一个窍门,更好的解决方案是使用多任务处理。

图形界面在这里以编程方式创建。如果使用GUIDE或在GUI Layout toolbox的帮助下构建,原理是相同的。

通过添加Log字段来报告文本框中的处理详细信息或类似于Log4Net(仅具有消息级别和消息值)的某些后端,可以进一步改进工具回调。或者通过为中间结果添加回调。例如,为什么不在每次修改设置时运行处理(即,只停止当前运行并且不需要每次手动点击'开始/取消'按钮),都可以对接口进行改进或修改。

有很多的可能性。在这里,只是提供一些地面应用程序开始(或不...)。