在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
功能(以迫使所述图形界面,以处理其消息)。
示例应用程序
的示例应用程序一起工作是非常基本的。它包含:
- 甲设置面板(仅与一个设置中,迭代的用于处理块的数目)
- 进度条
- 一个GO /取消按钮
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