MATLAB GUI Button with Keyboard Control - matlab

I have a button in a GUI. which the user presses to execute a Callback. But, I would like the user to be able to press the up arrow key instead of clicking to execute the callback.
EDIT: I am using GUIDE to make the GUI

Check out this thread:
http://www.mathworks.com/matlabcentral/answers/12034
Just slightly modifying the code from there to here (put the following in a file called testGUI.m
function testGUI
g = figure('KeyPressFcn', #keyPress)
MyButton = uicontrol('Style', 'pushbutton','Callback',#task);
function task(src, e)
disp('button press');
end
function keyPress(src, e)
switch e.Key
case 'uparrow'
task(MyButton, []);
end
end
end

Related

Can waitforbuttonpress be used with switch cases

I have used this piece of Code but it's not working. Can you help me where I am wrong here..
for i=1:10
keydown = waitforbuttonpress;
switch keydown
case'0'
disp(5);
case'1'
disp(6);
end
end
Thank you
You are using '0' and '1', when you should use 0 and 1.
'0' - char type '0' (ASCII value of '0' equals 48. double('0') = 48).
waitforbuttonpress documentation:
k = waitforbuttonpress blocks the caller's execution stream until the function detects that the user has clicked a mouse button or pressed a key while the figure window is active. The figure that is current when you call the waitforbuttonpress function is the only area in which users can press a key or click a mouse button to resume program execution. The return argument, k, can have these values:
0 if it detects a mouse button click
1 if it detects a key press
Modify your code as follows:
for i=1:10
keydown = waitforbuttonpress;
switch keydown
case 0
disp(5);
case 1
disp(6);
end
end

Matlab - Is there a way to capture messages sent to the workspace?

I'm working on a GUI (without GUIDE) in Matlab. The GUI will ultimately be compiled to an application and released to my coworkers.
My GUI calls some custom functions I wrote ages ago. These custom functions display status/progress messages to the workspace window.
As I understand it, I could have my executable write those messages to a log file, but then that leaves the user without any status updates on the GUI while the program is running.
I'm working on some pretty intensive 3D data manipulation, which has the potential to run for 5-10 minutes between function calls, so while I could provide status updates between function calls, it still leaves the end user with no idea what's going on and/or the appearance that the program locked up.
What I would like to do is to have something that works akin to the 'try-catch' method, where there's some way I can execute a function and capture messages intended for the workspace and redirect them to a uicontrol text box.
:EDIT:
I'm adding this for posterity, in the event anyone wants to use it. This is a functional demo that shows how to implement Peter's answer below.
First, create and save a function called "EndlessLoop":
function EndlessLoop(handles,loopCallback)
if nargin<1
handles = [];
loopCallback = #loop_Callback;
else
disp('Callback already set!');
end
tic;
abort = false;
while true
statusText = sprintf('Current Elapsed Time:\n%.2f',toc);
abort = loopCallback(handles,statusText);
if abort
statusText = sprintf('Abort request processed.\nEnding now.');
[~] = loopCallback(handles,statusText);
break;
end
pause(0.1);
end
return;
function abort = loop_Callback(~,myText)
clc;
abort = false;
disp(myText)
return;
Then, create a GUI that calls on EndlessLoop:
function TestGUI
close all;
myTest = figure('Visible','on','Units','normalized','Position',[0.1 0.1 0.8 0.8],'Name','Test GUI','NumberTitle','off');
set(myTest,'menubar','none');
handles = guihandles(myTest);
handles.goButton = uicontrol('Style','pushbutton','Units','normalized','Position',[0 0.5 0.5 0.5],'String','Go');
handles.abortButton = uicontrol('Style','pushbutton','Units','normalized','Position',[0 0 0.5 0.5],'String','Abort','Enable','off');
handles.statusText = uicontrol('Style','text','Units','normalized','Position',[0.5 0 0.5 1],'String','Press Go when ready.');
set(handles.goButton,'Callback',#goButton_Callback,'interruptible','on');
set(handles.abortButton,'Callback',#abortButton_Callback,'interruptible','on');
handles.abortButton.UserData = false;
guidata(myTest,handles);
return;
function goButton_Callback(hObject,~)
handles = guidata(gcbo);
hObject.Enable = 'off';
handles.abortButton.Enable = 'on';
EndlessLoop(handles,#StatusUpdate)
handles.abortButton.String = 'Abort';
handles.abortButton.Enable = 'off';
hObject.Enable = 'on';
pause(0.5);
handles.statusText.String = 'Press Go to start again.';
handles.abortButton.UserData = false;
guidata(gcbo,handles);
return;
function abortButton_Callback(hObject,~)
handles = guidata(gcbo);
if handles.abortButton.UserData
handles.abortButton.UserData = false;
hObject.String = 'Abort';
else
handles.abortButton.UserData = true;
hObject.String = sprintf('Abort pending...');
end
guidata(gcbo,handles);
return;
function abort = StatusUpdate(handles,statusText)
clc;
abort = handles.abortButton.UserData;
disp(handles.abortButton.UserData)
handles.statusText.String = statusText;
return;
A couple things I found when playing with this trying to get it to work:
I have been just adding variables to the handles structure for whatever I needed. In this case it would have been handles.abortRequest = false;. However, it appears that when I pass handles to the EndlessLoop function it becomes stale - handles never updates again. To get around this, I had to store what I wanted in the UserData section of the abortButton. I think this is because the handle to abortButton is still valid, because it hasn't changed, and I get fresh UserData because I'm able to poll with the valid handle. I can't access handles.abortRequest because it's not an object - I can't poll it; it simply exists, and it exists in the "snapshot" that was when I sent handles to EndlessLoop. At least, this is my understanding.
I needed to set the 'Interruptible' property of the goButton callback to 'on' in order for the abortButton to function while the process "hung" on EndlessLoop. With Interruptible set to off no other callbacks may be processed until that particular callback completes, which will never happen with endless loop.
So, in conclusion, this is a complete functional example that answers my question. Thanks to Peter for the answer - this also includes his ProTip of being able to pass an abort option back to the process that's taking a long time to complete. I've never used callbacks like this before so hopefully others will find this useful in the future.
This answer elaborates on my comment to the question.
Assume you have function that outputs stuff to the command window:
function out = longcomputation(param1, param2)
%
while(for_a_long_time)
process_one_step();
percent_complete = something;
fprintf('Step result: %f Complete: %f', stuff, percent_complete);
end
You can make the output function configurable by passing a function handle. Here I'm making it optional by testing nargin:
function out = longcomputation(param1, param2, outputfcn)
function display_progress_to_console(msg, percentage)
sprintf('%s, Complete %f', msg, percentage);
end
if(nargin < 3) % Supply a default output function if none passed in
outputfcn = #display_progress_to_console;
end
while(for_a_long_time)
process_one_step();
percent_complete = something;
msg = sprintf('Step result: %f', stuff);
outputfcn(msg, percent_complete);
end
Now, in your GUI, you can define and pass in a different output callback. This can live right in your GUI code so that the function has access to the GUI objects you need.
ProTip: In addition, have this callback function return true or false to signal the user's desire to abort. The GUI can then present a cancel button to drive that return value, and the long-running code can periodically send the status message AND check if abort has been requested.
You could potentially use the built-in diary functionality to accomplish something similar to what you're trying to do.
diary on % Uses "diary" for filename
diary('logfile.log') % Custom filename
This will write all command line output to the specified file. Then you can periodically poll this file and update your uicontrol with the contents (or last few lines if you want).
logfile = 'logfile.log';
diary(logfile);
u = uicontrol('style', 'text');
% Check every 5 seconds
t = timer('Period', 5, ...
'ExecutionMode', 'FixedRate', ...
'TimerFcn', #(s,e)populate(s));
start(t);
function populate(src)
fid = fopen(logfile, 'rb');
contents = fread(fid, '*char').';
set(src, 'String', contents);
fclose(fid);
end

matlab's GUI KeyPressFcn

I am using the KeyPressFcn method for the edit box to test whether enter is pressed. I can use call_back but there is not event_data call_back function.
If I press one time on the button of Enter, than text doesn't rewrite, but if I double time on the button of Enter (speedly), than text rewrite.
What reasons this behaviour?
function WriteData(val, name, ind)
global solver;
switch ind
case {14, 15}
value = strcat('#(t)', val);
case 16
value = strcat('#(x)', val);
case {17, 18}
value = strcat('#(x,t)', val);
end
eval(strcat('solver.', name, ' = ', num2str(val) ) );
function edit1_KeyPressFcn(hObject, eventdata, handles)
val = get(hObject, 'String');
[~, ~, var] = GetActiveData(handles.listbox1);
ind = get(handles.listbox1, 'Value');
if (strcmp(eventdata.Key, 'return') )
WriteData(val, var, ind );
end
According to the documentation found in UIControl Properties (http://www.mathworks.com/help/matlab/ref/uicontrol-properties.html;jsessionid=49b9dc47d9f964ec95a4fe2cc9f3),
This callback function executes when the uicontrol object has focus and the user presses a key. If you do not define a function for this property, MATLAB passes key presses to the parent figure. Repeated key presses retain the focus of the uicontrol, and the function executes with each key press. If the user presses multiple keys at approximately the same time, MATLAB detects the key press for the last key pressed.
More simply put, the Callback will be called when you press enter the first time and the KeyPressFcn will be applied on the second press.

Access to the callback function of checkbox

I have some checkbox and a push button to select all of them.
Code of my button "Select all" :
for i = 1:5
set(sprintf('handles.check%d',i),'value', 1)
end
But, I would like to go to the checkbox callback function each time I select one of them. How can I do this ? Because for the moment, all my check box are selected when I push the button "Select all" but the code into each checkbxo is not executed. My code in a checkbox is :
function check1_Callback(hObject, eventdata, handles)
if(get(hObject ,'Value') == 1)
ind=1;
assignin('base','ind',ind);
end
end

Close MATLAB GUI with a dialog

I'm doing a GUI with GUIDE and want to close the figure with a dialog.
I have a button with this
selection = questdlg('Close This Figure?',...
'Close Request Function',...
'Yes','No','Yes');
switch selection,
case 'Yes',
delete(gcf)
case 'No'
return
end
and it works fine but I want the main button to do the same thing.
I tryed to put this next to
function varargout = file_name(varargin)
...
but won't work. Any suggestions?
Use above code in a function say:
%Save in myclose_callback.m
function myclose_callback(src,evnt)
selection = questdlg('Close This Figure?',...
'Close Request Function',...
'Yes','No','Yes');
switch selection,
case 'Yes',
delete(gcf)
case 'No'
return
end
end
Then use:
%From other .m script or from command window
figure('CloseRequestFcn',#myclose_callback)
To make this as your default callback for all figures, use:
set(0,'DefaultFigureCloseRequestFcn',#myclose_callback)