2015-02-06 325 views
5

我正在使用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

回答

6

下面是應該工作一招:在某處的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

5

最佳的解決辦法是使用獨立的線程(一個用於用戶界面和一個用於處理)也許使用並行工具箱。無論如何,這將是非常複雜的同步兩個。

所以,這裏是一個簡單的解決方案,它僅依賴於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(僅具有消息級別和消息值)的某些後端,可以進一步改進工具回調。或者通過爲中間結果添加回調。例如,爲什麼不在每次修改設置時運行處理(即,只停止當前運行並且不需要每次手動點擊'開始/取消'按鈕),都可以對接口進行改進或修改。

有很多的可能性。在這裏,只是提供一些地面應用程序開始(或不...)。