detection of key press when plotting in matlab - matlab

I would like to detect pressing of key when plotting position of pendulum and getting position of pendulum to variable, when the key is being pressed. I have no idea how to do it, I tried to search, but I have not found anything helpful. I tried to use WindowKeyPressFcn callback, but I cannot find a way to use it. I tried this way:
function keyPressCallback(source,eventdata)
keyPressed = eventdata.Key;
if strcmpi(keyPressed,'space')
disp('success');
end
end
set(f,'WindowKeyPressFcn',#keyPressCallback);
But I get an error when running the script:
There is no WindowKeyPressFcn property on the Root class.

following Navan's and Cris Luengo's comments, I rearranged the script and it runs successfully for me
f = figure;
set(f,'WindowKeyPressFcn',#keyPressCallback);
plot(rand(10,2))
function keyPressCallback(source,eventdata)
keyPressed = eventdata.Key;
if strcmpi(keyPressed,'space')
disp('success');
end
end

Related

set Matlab WindowButtonDownFcn and preserve default behavior

can I manually set WindowButtonDownFcn and selectively overwrite the right or middle-click, while preserving default behavior? Ultimate goal would be to copy figure to clipboard on some click.
set(gcf,'WindowButtonDownFcn',#(src,~) disp(src.SelectionType)); %this seemingly always overwrites default behavior of figure click
I tried this with following error msgs (scroll right)
listener(gcf,'WindowButtonDownFcn',#(src,~) disp(src.SelectionType)) %Event 'WindowButtonDownFcn' is not defined for class 'matlab.ui.Figure'.
listener(get(gcf,'parent'),'WindowButtonDownFcn',#(src,~) disp(src.SelectionType)) %Event 'WindowButtonDownFcn' is not defined for class 'matlab.ui.Root'
handle(gcf).addlistener(handle(gcf),'WindowButtonDownFcn',#(src,~) disp(src.SelectionType)) %Unrecognized method, property, or field 'addlistener' for class 'matlab.ui.Figure'.
and several more permutation using handle and event.listener with no success
Tested in Matlab 2019a.
EDIT: here's a template function to use with modifiers based on matlabgui's kind answer
%copies figure to clipboard when [control]+[right-click] anywhere on figure window (and leaving default functionality intact)
figure; plot(randi(100,1,100)) %random figure
addlistener ( gcf, 'WindowMousePress', #(src,~) myFavFunc(src,[]))
function myFavFunc(src,~)
if strcmp(src.SelectionType,'alt') && numel(src.CurrentModifier)==1 && strcmp(src.CurrentModifier,'control')
print -clipboard -dmeta
disp('copied figure to clipboard')
end
end
I dont know why Matlab hide some of the events for figures, you can get a list here:
hFig = figure;
mc = metaclass(hFig);
disp ( {mc.EventList.Name}' ) ;
From that info you can then add a listener to the mouse press event:
hFig = figure;
addlistener ( hFig, 'WindowMousePress', #(src,~)disp('myCallback' ))
That will leave the standard figure callback alone, instead of the disp command get it to run a function where you look at the figure property SelectionType to determine which mouse button was pressed. You could extend it to use the CurrentModifier property to determine if Ctrl, Shift or Alt was pressed to further customise it.

Draw using an existing figure object/canvas in MATLAB

I am trying to animate a clock hand's movement using MATLAB. I created 'draw_clock()' program/script in a file named 'draw_clock.m' that goes something like this.
function draw_clock()
set_figure();
draw_clock_hands();
end
function set_figure()
figure;
hold on;
axis off;
title('Clock');
end
Then I have a script file named 'animate_clock.m' that has something like this:
hours = 0:12;
minutes = 0:59;
for i = 1:numel(hours)
for j = 1:numel(minutes)
draw_clock();
pause(0.05);
refresh;
end
end
When I run 'animate_clock.m', new window/clock figure for every frame is opened instead of redrawing on the same canvas/figure. I understand why this is happening because 'set_figure()' is being called every time 'draw_clock()' is called. I'm new to MATLAB, so if there's a way to stop creating new figure with the code skeleton above. I guess if I can detect if there's a figure object already opened, then I can skip calling 'set_figure()' inside 'draw_clock()' next time it is being called?
Thank you in advance for your answers!
So after searching and reading the doc a bit, I think there are a couple of different ways to detect if a matlab figure already exists. One that I found useful (and relatively simple) is to:
- assign the 'Name' property to the figure window
- find if an object with the assigned name exists using 'findobj(...)' method
- if figure already exists, use 'hold on' to reuse the old figure
- else, create a new figure with the name 'figure('Name', 'foo figure')'
For my case, 'set_figure()' method will become something like this:
function set_figure()
fig_name = 'My Clock';
if isempty(findobj('Name', fig_name))
figure('Name', fig_name);
end
hold on;
axis off;
end
Hope someone can come and improve it to become more robust. :)

Matlab adding KeyListener to existing button

I've written a Matlab program which counts different values when are particular button is pressed (so far just the numbers of "yes" and "no"). I'm trying to add a key listener so that when I press, for example, n on the keyboard the button is pressed, or the same actions are completed. I have tried the addListener and keyfunclistener functions but neither seems to be working.
Here is an example of the button:
no=uicontrol(h_fig,'callback',countnonerve,'position',[.65 .07 .1 .08],'string','No','style','pushbutton','Units','normalized');
Any suggestions? It would be very helpful I'm not familiar with MatLab
You could try using the KeyPressFcn property of the figure to record/capture individual key presses:
function keypress_Test
h = figure;
set(h,'KeyPressFcn',#keyPressCb);
function keyPressCb(src,evnt)
disp(['key pressed: ' evnt.Key]);
end
end
The above code can be pasted into a file and saved as keypress_Test.m. A figure is created and a callback assigned to the KeyPressFcn property.
It can be easily adapted for your GUI. Wherever you have access to the figure handles (probably the h_fig from above) just add set(h_fig,'KeyPressFcn',#keyPressCb); and paste the keyPressCb code into the same file.
If you are counting the number of times a certain key is pressed, then you will have to save this information somewhere..probably to the handles structure. Is that the case? If so, then you can easily access this from the callback
function keyPressCb(src,evnt)
disp(['key pressed: ' evnt.Key]);
% get the handles structure
handles = guidata(src);
if ~isempty(handles)
% do something here - increment count for evnt.Key
% save the updated count
guidata(src,handles);
end
end
Try it out and see what happens!

MATLAB: Pause program and await keypress

I am writing a program in which at some point a graph is plotted and displayed on screen. The user then needs to press 'y' or 'n' to accept or reject the graph. My current solution uses the PsychToolbox (the actual solution doesn't need to), which includes a command called 'KbCheck' which checks at the time of calling the state of all the keyboard buttons. My code looks like this:
function [keyPressed] = waitForYesNoKeypress
keyPressed = 0; % set this to zero until we receive a sensible keypress
while keyPressed == 0 % hang the system until a response is given
[ keyIsDown, seconds, keyCode ] = KbCheck; % check for keypress
if find(keyCode) == 89 | find(keyCode) == 78 % 89 = 'y', 78 = 'n'
keyPressed = find(keyCode);
end
end
The problem is, that the system really does 'hang' until a key is pressed. Ideally, I would be able to scroll, zoom, and generally interact with the graphs that are plotted onscreen so that I can really decide whether or not I want to press 'y' or 'n'!
I have tried adding 'drawnow;' into the while loop above but that doesn't work: I still am unable to interact with the plotted graphs until after I've accepted or rejected them.
The solution doesn't have to use PsychToolbox; I assume there are plenty of other options out there?
Thanks
I'd use the input function:
a = input('Accept this graph (y/n)? ','s')
if strcmpi(a,'y')
...
else
...
end
Although admittedly it requires two keypresses (y then Enter) rather the one.
Wait for buttonpress opens up a figure, which may be unwanted. Use instead
pause('on');
pause;
which lets the user pause until a key is pressed.
Why not using waitforbuttonpress instead?
Documentation: http://www.mathworks.fr/help/techdoc/ref/waitforbuttonpress.html
You don't want to use waitforbuttonpress since it locks the figure gui (no zooming, panning etc).
pause can cause the command window to steal the focus from the figure.
The solution I find to work best is to open the figure with a null keyPressFcn in order to avoid focus problems:
figure('KeyPressFcn',#(obj,evt) 0);
and then wait for CurrentCharacter property change:
waitfor(gcf,'CurrentCharacter');
curChar=uint8(get(gcf,'CurrentCharacter'));
Wait for key press or mouse-button click:
Example:
w = waitforbuttonpress;
if w == 0
disp('Button click')
else
disp('Key press')
end
for more information visit:
http://www.mathworks.com/help/matlab/ref/waitforbuttonpress.html
The waitforbuttonpress command is good but is triggered by either a mouse click or a key press. If you want it to trigger only from a key press, you can use the following hack:
while ~waitforbuttonpress
end

How do I use CurrentCharacter in matlab?

I am trying to use the CurrentCharacter property in matlab but I don't know how it works. Could somebody give me an example? I have tried to use get(gcf,'CurrentCharacter');
Run this code and start pressing the keys on the keyboard. Observe the output on the Command Window.
f = figure;
set(f, 'KeyPressFcn', #(x,y)disp(get(f,'CurrentCharacter')))
From MATLAB documentation:
CurrentCharacter
single character
Last key pressed. MATLAB sets this property to the last key pressed in
the figure window. Use CurrentCharacter to obtain user input.
I'm not sure how you're intending to use it, but here's a simple way to demonstrate it;;
Create a figure
Click on the figure (bring it to front in the OS GUI)
Type a character (it will likely appear in your command window)
Enter kkey = get(gcf,'CurrentCharacter') in your command window
By doing this you set kkey to the first character you typed while your figure window was active.