how can i stop while loop immediately by a push button?
9 次查看(过去 30 天)
显示 更早的评论
Here is my code. Everything is correct in it , but if i push the stop button it waits for the end of the loop, But i dont want to wait, i would like to stop it immediately by the button press. How can i do that kind of thing? Thanks very much for any idea!
moreWork = true;
while moreWork
I = imcrop(handles.hImage); imshow(I,'Parent', handles.pic1); drawnow
I2 = imcrop(handles.hImage); imshow(I2,'Parent', handles.pic2); drawnow
I3 = imcrop(handles.hImage); imshow(I3, 'Parent', handles.pic3); drawnow
I4 = imcrop(handles.hImage); imshow(I4,'Parent', handles.pic4); drawnow
data = get(handles.figure1, 'UserData');
if data.stop == true
data.stop = false; %reset for next time
set(handles.figure1,'UserData',data);
moreWork = false; %to stop the loop
drawnow
end
end
end
function stop_Callback(hObject, eventdata, handles)
data = get(handles.figure1, 'UserData');
data.stop = true;
set(handles.figure1,'UserData',data);
drawnow
end
0 个评论
回答(4 个)
Andrew Reibold
2014-10-23
编辑:Andrew Reibold
2014-10-24
I think you need to make sure 'Interupt' is set to 'Enabled' or 'On' or something like that. Is it possible?
0 个评论
Image Analyst
2014-10-23
I haven't found a way. What I do is to have a "Finish now" checkbox. For some reason it will update a checkbox, which you can check at various places in your loop, whereas trying to set a "FinishNow" flag (global variable) via a pushbutton won't update the value. Be sure to set the visible property of the checkbox to 'on' right before your loop starts and to set the value to 0 and visibility to 'off' once the loop exits.
finishNow = false;
% Display the checkbox.
set(handles.chkFinishNow, 'Visible', 'on');
while ~finishNow
% Do stuff
% Check if user want to finish now
finishNow = get(handles.chkFinishNow, 'value');
end
% Clear the checkbox and hide it.
set(handles.chkFinishNow, 'value', 0);
set(handles.chkFinishNow, 'Visible', 'off');
0 个评论
Matt Tearle
2014-10-23
编辑:Matt Tearle
2014-10-23
When you say "i would like to stop it immediately by the button press", do you mean you'd like to interrupt the imcrop calls? The way you have it right now, the moreWork check is done only at the beginning of each loop and moreWork can't be changed until after the four imcrop / imshow operations have completed. You could certainly check the value of stop from the figure's UserData before each imcrop, but once a command is issued in a callback, you can't interrupt it. (You can interrupt a callback -- that's the default behavior, but not commands already underway. See code below for an example.) Furthermore, the doc for imcrop explicitly says "Note: With these interactive syntaxes, the cropping tool blocks the MATLAB command line until you complete the operation." So the best you're going to be able to do is to interrupt between commands (and you'll have to check for that).
Here's an example of interruption behavior. Change the size of the random numbers being generated so that it's big enough that you can see the pause (but not so big that it grinds your machine to a halt!). If you click "stop" right after it starts calculating numbers, you'll see that the pause is still there until it's done with that line.
function interruptingcow
f = figure;
set(f,'UserData',false)
uicontrol(f,'Style','pushbutton',...
'Units','normalized','Position',[0.1 0.1 0.2 0.2],...
'Callback',@makenumbers,'String','Start');
uicontrol(f,'Style','pushbutton',...
'Units','normalized','Position',[0.1 0.5 0.2 0.2],...
'Callback',@interrupt,'String','Stop');
end
function makenumbers(obj,~)
f = get(obj,'Parent');
set(f,'UserData',true)
while (get(f,'UserData'))
disp('Making numbers...')
x = rand(200000000,1);
disp('I made some numbers')
drawnow
end
end
function interrupt(obj,~)
f = get(obj,'Parent');
set(f,'UserData',false)
disp('MOOOOO!')
end
[If you move the drawnow above the disp (in makenumbers), you'll see that the interrupt happens there, but you still have to wait for the x = rand... command to complete.]
0 个评论
Matt Tearle
2014-10-24
Once the first imcrop call is complete, the imshow command is executed, then data.stop is checked. That gives you the blink of an eye to hit the stop button. If you miss that window, the code moves on to the next imcrop. As I mentioned before, once that line of code is reached, that function call has to run to completion before another callback can interrupt execution.
So, bottom line: there's no simple way around this.
Two options you could consider: change the behavior to require a user response after each imcrop / imshow (e.g. one button that says "do another" and one that says "I'm all done"); and/or do the crop selection yourself.
Here's an example that might help:
function selection
x = imread('street1.jpg');
f = figure;
ax = axes('Parent',f,'Units','normalized','Position',[0.1 0.3 0.8 0.6]);
img = imshow(x,'Parent',ax);
% Keep some important state information
figdata.ax = ax;
figdata.img = img;
figdata.startpoint = [];
% Make a selection highlight
figdata.selection = patch([0 0 1 1],[0 1 1 0],'w',...
'FaceAlpha',0.2,'EdgeColor','k','Visible','off');
set(f,'UserData',figdata)
uicontrol(f,'Style','pushbutton',...
'Units','normalized','Position',[0.4 0.1 0.2 0.05],...
'String','Start cropping','Callback',@croptoggle);
end
% Callback for switching cursor to crosshairs and highlighting selection
function mousepos(obj,~)
data = get(obj,'UserData');
% Current mouse location (in axis units)
cp = get(data.ax,'CurrentPoint');
cp = cp(1,1:2);
% Is the mouse within axis limits?
% (If so, position - min/max will be negative/positive, respectively...
inx = prod(cp(1) - get(data.ax,'XLim'));
iny = prod(cp(2) - get(data.ax,'YLim'));
% ...so product will be < 0
if ((inx < 0) && (iny < 0))
% Within image -> make a crosshair pointer
set(obj,'Pointer','crosshair')
else
% Outside image -> reset pointer
set(obj,'Pointer','arrow')
end
% If a start point has been defined, draw the highlight rectangle
if ~isempty(data.startpoint)
x1 = data.startpoint(1);
y1 = data.startpoint(2);
set(data.selection,'XData',[x1 x1 cp(1) cp(1)],...
'YData',[y1 cp(2) cp(2) y1],'Visible','on')
end
end
function startcrop(obj,~)
% Was the click within the image? (If not, ignore it)
if strcmp(get(obj,'Pointer'),'crosshair')
% Set callback for button release
set(obj,'WindowButtonUpFcn',@finishcrop)
% Record the start point
data = get(obj,'UserData');
cp = get(data.ax,'CurrentPoint');
data.startpoint = cp(1,1:2);
set(obj,'UserData',data)
end
end
function finishcrop(obj,~)
data = get(obj,'UserData');
% Was the release within the image?
if strcmp(get(obj,'Pointer'),'crosshair')
% Get the current point and the initial point
cp = get(data.ax,'CurrentPoint');
pts = [data.startpoint;cp(1,1:2)];
% Get initial location and extent (allowing for the first point to be
% below or right of the final point)
x = min(pts);
dx = abs(diff(pts));
% As long as the box had some size (in both directions), zoom in
if all(dx>0)
data.img = imshow(imcrop(get(data.img,'CData'),...
[x(1) x(2) dx(1) dx(2)]),'Parent',data.ax);
% imshow deletes the highlight box, so remake it (invisible)
data.selection = patch([0 0 1 1],[0 1 1 0],'w',...
'FaceAlpha',0.2,'EdgeColor','k','Visible','off');
end
else
% No -> delete the highlight box
set(data.selection,'Visible','off')
end
% Either way, no need for the highlight box -> delete the starting point
data.startpoint = [];
% Update all the figure information
set(obj,'UserData',data)
end
function croptoggle(obj,~)
f = get(obj,'Parent');
% Toggle the button state
if strcmp(get(obj,'String'),'Start cropping')
set(obj,'String','Done cropping')
set(f,'WindowButtonMotionFcn',@mousepos)
set(f,'WindowButtonDownFcn',@startcrop)
else
set(obj,'String','Start cropping')
set(f,'WindowButtonMotionFcn',[])
set(f,'WindowButtonDownFcn',[])
end
end
[BTW, do you have 14b? I wrote all that in pre-14b syntax (I hope!). Some of this could be cleaned up a little with the new graphics objects.]
0 个评论
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Interactive Control and Callbacks 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!