我正在使用MATLAB R2014b中的GUIDE
設計GUI。我的程序有一個長循環(需要2〜5小時處理)。我想在我的GUI中有一個按鈕,用戶每次都要停止該過程(GUI基於循環的結果不斷更新圖形和文本)。類似於在結束循環之後按Control+C
。我怎樣才能實現這個?在MATLAB中的進程中停止GUI
PS。 我不想讓MATLAB刪除我的工作區。用戶可以通過更改GUI中的某些選項,使用先前加載的數據和工作空間來繼續該過程。
我正在使用MATLAB R2014b中的GUIDE
設計GUI。我的程序有一個長循環(需要2〜5小時處理)。我想在我的GUI中有一個按鈕,用戶每次都要停止該過程(GUI基於循環的結果不斷更新圖形和文本)。類似於在結束循環之後按Control+C
。我怎樣才能實現這個?在MATLAB中的進程中停止GUI
PS。 我不想讓MATLAB刪除我的工作區。用戶可以通過更改GUI中的某些選項,使用先前加載的數據和工作空間來繼續該過程。
下面是應該工作一招:在某處的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
截圖:
希望幫助!
這是工作,因爲在['暫停](http://fr.mathworks.com/help/matlab/ref/pause.html)matlab繼續處理HG回調。如果在處理循環中沒有「暫停」或「drawnow」,GUI將會停止(單線程執行模型)。 – CitizenInsane 2015-02-07 16:47:54
那麼一個循環應該是完整的,之後我們可以停止這個過程?我們無法在循環工作中停止流程?謝謝。 – user2991243 2015-02-09 16:35:41
是的,如果你願意,你可以在中間停下來;嘗試代碼自己看:) – 2015-02-09 16:37:55
最佳的解決辦法是使用獨立的線程(一個用於用戶界面和一個用於處理)也許使用並行工具箱。無論如何,這將是非常複雜的同步兩個。
所以,這裏是一個簡單的解決方案,它僅依賴於anonymous
功能(委派接口處理塊外部刷新)和drawnow
功能(以迫使所述圖形界面,以處理其消息)。
示例應用程序
的示例應用程序一起工作是非常基本的。它包含:
NB:源代碼很長(大約250行,主要是由於gui的創建),所以我放棄了它here。
創建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
這是長一點,總之這是一樣的。如果我們處於跑步模式,我們只是表示我們想停止;否則,界面處於正常模式,我們開始處理。
功能tryReadSettings
,enterComputationMode
和leaveComputationMode
只是膠以更新控制在界面和漂亮報告錯誤或取消。
結論
我們設計了一個響應的圖形界面僅依靠drawnow
和anonymous
功能。這當然只是一個竅門,更好的解決方案是使用多任務處理。
圖形界面在這裏以編程方式創建。如果使用GUIDE或在GUI Layout toolbox的幫助下構建,原理是相同的。
通過添加Log
字段來報告文本框中的處理詳細信息或類似於Log4Net(僅具有消息級別和消息值)的某些後端,可以進一步改進工具回調。或者通過爲中間結果添加回調。例如,爲什麼不在每次修改設置時運行處理(即,只停止當前運行並且不需要每次手動點擊'開始/取消'按鈕),都可以對接口進行改進或修改。
有很多的可能性。在這裏,只是提供一些地面應用程序開始(或不...)。
嗨,你是否嘗試過下面的答案?他們是否爲你工作? – 2015-02-23 17:58:51
這兩個答案都很好:-)。爲什麼我們不能選擇接受的兩個答案:-) – user2991243 2015-02-24 14:57:05
哈哈我不知道:)但是你可以選擇一個,這樣線程將被關閉。謝謝! – 2015-02-24 14:58:58