You have two routes you can take.
1) You can take even-driven approach and register KeyPressFcn
callback for the current figure. The catch is that Matlab is single threaded*, so as long as your loop continuously executes some code, event will not be handled. A workaround would be to insert either drawnow
or pause
statements within your loop. That will halt the main thread execution and would process outside events, such as our key press. In the callback you would need to change the state of some flag, e.g. an object property / appdata of some graphics handle, or even a global variable (which I would advise against). You would then be able to query from within the loop and break if you see the flag changing.
function test()
hFig = figure();
setappdata(hFig, 'space_pressed', false);
set(hFig, 'KeyPressFcn', @keyPressedFcn);
while true
A = randn(10000); % doing some stuff
pause(0.01);
flag = getappdata(hFig, 'space_pressed');
if flag
break;
end
fprintf('Still running...\n');
end
fprintf('Finished!\n');
end
function keyPressedFcn(hFig, event)
fprintf('Pressed character: "%s"...\n', event.Character);
if strcmp(event.Character, ' ')
setappdata(hFig, 'space_pressed', true);
end
end
Sample output:
>> test
Still running...
Still running...
Pressed character: "h"...
Still running...
Still running...
Pressed character: " "...
Finished!
2) Second approach would be to poll for CurrentCharacter
. Note that it also requires you to halt execution by using pause
/ drawnow
for the character stroke to be processed. A side-effect of this approach is that after a key press the focus moves to command window, and the character also appears there.
function test()
hFig = figure();
set(hFig, 'CurrentCharacter', '^'); % some other character
drawnow();
while true
A = randn(10000); % doing some stuff
pause(0.01);
char = get(hFig, 'CurrentCharacter');
if strcmp(char, ' ')
break;
end
fprintf('Still running...\n');
end
fprintf('Finished!\n');
end
- EDIT elaborating on the threading in Matlab:
Matlab GUI components actually run on EDT thread, which is separate to the one where the main execution is happening (unless you create java GUI objects explicitly without using javaObjectEDT
, which you should avoid) - this is what allows GUI components to visually react on some actions you take which do not require synchronization with the main execution thread, like visually changing button state when clicking on it. But to actually get the callback to run and change the state of your workspace inside the execution thread, you need to let Matlab synchronize the two threads. This is what pause
/drawnow
helps to do - it halts whatever you've been doing on the execution thread which allows your GUI callbacks to execute in the meantime. drawnow
would clear the whole pending queue before returning execution to your original code block, while pause
will potentially only process some of the callbacks until the time runs out. You may observe this if you set pause
argument to a tiny fraction of a second and make lots of actions - not all will be processed.
You may notice some slight changes in behavior between different Matlab releases - the two threads seem to become slightly more independent over time. There is surprisingly little official information available on this - most of it is based on experience and various answers scattered across Matlab central, like this and that, and obviously fantastic articles on the UndocumentMatlab, like the one linked above.