This is a MATLAB GUI. And I have a while loop running. But while in the loop i need to use keyboard inputs which are a different callback. Is there a way or is it possible to execute that callback while it is in the loop?
Note: I am using GUIDE
Yes, this is possible. You just need to get the character data from the keypress callback to the callback that is in a loop. One way of doing this is via the figure guidata.
For example, if your loop is running from a button callback and you want to see a keypress on the figure you could use the following:
Button Callback
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
fig = get(hObject,'Parent');
for i=1:1000
pause(0.01);
% Get the latest guidata
handles = guidata(fig);
if isfield(handles,'KeyData' ) && ~isempty(handles.KeyData)
fprintf(1,'Pressed : %s\n', handles.KeyData.Character);
% Clear the keydata we have now handled.
handles.KeyData = [];
guidata(fig,handles);
end
end
Figure keypress callback
% --- Executes on key press with focus on figure1 and none of its controls.
function figure1_KeyPressFcn(hObject, eventdata, handles)
% Store the keypress event data for use in the looping callback
handles.KeyData = eventdata;
guidata(hObject,handles);
Related
I have a simple MATLAB GUI Code, find attached. All it does is when a button is pressed it runs a function.
However when I press this button twice, it is throwing an error
Undefined function 'GUI' for input arguments of type 'struct'.
Error in #(hObject,eventdata)GUI('pushbutton1_Callback',hObject,eventdata,guidata(hObject))
Error while evaluating uicontrol Callback
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
set(handles.pushbutton1, 'enable','off');
output = randomFunction();
a = 1
while(1)
a = a+1
if a == 4
break;
end
end
set(handles.pushbutton1, 'enable','on');
The issue is that randomFunction must either change the current working directory or modify your PATH such that the GUI function (GUI.m) is no longer on the path and able to be found when you click the button the second time.
If you'd like to stop this behavior you have two options
The preferred option would be to modify randomFunction to not make this modification. A function should always the user's environment to the way that it was before being called. You can easily do this by using onCleanup within randomFunction
function randomFunction()
folder = pwd;
cleanup = onCleanup(#()cd(folder));
% Normal contents of randomFunction
end
The other option within randomFunction though is to never use cd. This is the best practice. You can use full file paths instead to access files
filename = fullfile(folder, 'image.png');
imread(filename)
If you can't modify randomFunction you can modify your callback to remember what the current directory was before calling the function and then change it back after randomFunction completes. I would actually recommend using onCleanup to do this to ensure that the directory is changed back even if randomFunction errors out
function pushbutton1_Callback(hObject, eventdata, handles)
set(handles.pushbutton1, 'enable', 'off');
% Make sure that when this function ends we change back to the current folder
folder = pwd;
cleanup = onCleanup(#()cd(folder));
output = randomFunction();
a = 1
while(1)
a = a+1
if a == 4
break;
end
end
set(handles.pushbutton1, 'enable','on');
Is there a general purpose way to determine when a Matlab GUI callback function begins and then has returned to the dispatcher?
I want to lock out user interaction while callbacks are running to completion and also show busy status while callbacks are running. Is there a dispatcher accessible where I can insert this code, or do I have to put it into every callback function.
I am aware of the modal waitbar but I want to avoid using that as much as possible. (They can't be killed gracefully.)
I suggest to add a wrapper function, that wraps all original UIControl callback functions.
The wrapper function does the following:
Locks (disables) all GUI UIControl objects.
Executes original callback function.
Enables all GUI UIControl after original callback returns.
You can also start a timer before original callback, and stop the timer when callback returns (the timer can simulate a wait bar using an image built int to the main GUI [image inside a small axes]).
Example (assuming GUI was created using guide tool):
% --- Executes just before untitled1 is made visible.
function untitled1_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to untitled1 (see VARARGIN)
% Choose default command line output for untitled1
handles.output = hObject;
%Add wrapper function to each UIControl callback.
A = findall(hObject.Parent, 'Type', 'UIControl');
for i = 1:length(A)
set(A(i), 'Callback', {#wrapper, A(i).Callback});
end
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes untitled1 wait for user response (see UIRESUME)
% uiwait(handles.figure1);
function wrapper(ObjH, EventData, origCallback)
disp('Do somthing before callback begins...');
%You can also start a timer.
%Disable all UIControl objects, before executing original callback
A = findall(ObjH.Parent, 'Type', 'UIControl');
for i = 1:length(A)
set(A(i), 'Enable', 'off');
end
%Execute original callback.
feval(origCallback, ObjH, EventData);
disp('Do somthing after callback ends...');
%You can also stop the timer.
%Enable all UIControl objects, after executing original callback
for i = 1:length(A)
set(A(i), 'Enable', 'on');
end
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
pause(1);
set(handles.pushbutton1, 'BackgroundColor', [rand(1,1), rand(1,1), rand(1,1)]);
You can generally lock user interaction with the waitfor command. It is designed to do exactly what you ask.
You can make your callback function update a handle property when it's finished, which can cause waitfor to exit. If that handle property you're updating also happens to hold the result of a tic / toc operation timing the duration of your callback function, then you kill two birds with one stone :)
I built this GUI in Matlab to interact with data. I have created a data environment object to facilitate interaction with data. This object triggers events and I want the GUI to listen to some of these events. So, as you can see in the code below I use the instruction addlistener to link the event to a local function. The issue is that this local function has no access to the GUI handles, do you have any thought on how tho solve this issue? Thanks
function varargout = myGUI(varargin)
...
end
function varargout = myGUI_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
dataEnv = getappdata(hObject.Parent, 'ratData');
addlistener(dataEnv,'TrialChanged',#respond_TrialChanged);
end
function respond_TrialChanged(dataEnv, eventData)
do_something(handles) % I want to access the GUI handles here
end
function do_something(handles)
...
end
You can use anonymus functions as callbacks which will provide the handles. For example:
function varargout = myGUI_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
dataEnv = getappdata(hObject.Parent, 'ratData');
addlistener(dataEnv,'TrialChanged',#(e,d) respond_TrialChanged(e,d,handles.output));
end
function respond_TrialChanged(dataEnv, eventData, handles)
do_something(handles) % I want to access the GUI handles here
end
The tird argument to the anonymous functions is handle or handles, or whatever you want to pass within the scope of myGUI_OutputFcn into respond_TrialChanged.
Hope this helps.
I am currently evaluating GUIs in MATLAB and was wondering how to maximize a GUI window on startup, without the need for user interaction. The function I am using is stated hereafter and works fine if called on a button press, but calling it in the figure's OpeningFcn won't help.
http://www.mathworks.com/matlabcentral/fileexchange/25471-maximize
Any help on some startup section to place the function call, which is executed after the GUI window has been drawn? I searched for solutions related to startup code in MATLAB GUIs, but there were no results to date.
Thanks in advance for your efforts.
Since many people seem to be interested in this and there is still no public solution, I will describe my approach:
In the YourGUIName_OpeningFcn(hObject, eventdata, handles, varargin) function, append the following lines:
% Initialize a timer, which executes its callback once after one second
timer1 = timer('Period', 1, 'TasksToExecute', 1, ...
'ExecutionMode', 'fixedRate', ...
'StartDelay', 1);
% Set the callback function and declare GUI handle as parameter
timer1.TimerFcn = {#timer1_Callback, findobj('name', 'YourGUIName')};
timer1.StopFcn = #timer1_StopFcn;
start(timer1);
Declare the timer1_Callback and timer1_StopFcn functions:
%% timer1_Callback
% --- Executes after each timer event of timer1.
function timer1_Callback(obj, eventdata, handle)
% Maximize the GUI window
maximize(handle);
%% timer1_StopFcn
% --- Executes after timer stop event of timer1.
function timer1_StopFcn(obj, eventdata)
% Delete the timer object
delete(obj);
Declare the maximize function:
function maximize(hFig)
%MAXIMIZE: function which maximizes the figure withe the input handle
% Through integrated Java functionality, the input figure gets maximized
% depending on the current screen size.
if nargin < 1
hFig = gcf; % default: current figure
end
drawnow % required to avoid Java errors
jFig = get(handle(hFig), 'JavaFrame');
jFig.setMaximized(true);
end
Source of the maximize function:
http://www.mathworks.com/matlabcentral/fileexchange/25471-maximize
I am having trouble stopping execution of a while-Loop which is activated by pressing a Togglebutton and is meant to stop when the Togglebutton is "untoggled".
The code inside calls a function that causes a steppermotor connected to an Arduino to do one step. The function needs about 10ms to execute.
Stopping works fine if i add a pause after the function call, but as the Onestep-function already needs longer to execute than I wish for and minimum pause-time is 10ms this solution isn't really pleasing.
% --- Executes on button press in Aplus_button.
function Aplus_button_Callback(hObject, eventdata, handles)
while get(hObject,'Value')
Onestep(1, 'Motor', handles)
% if i add a pause() here it works
end
I am thankful for any hints on how I get this executed as fast as possible.
Try adding a call to drawnow in your loop, where you have the pause. This should poll the GUI for any changes in state.
Since your Onestep function is so quick, you might only want to call drawnow only every 10th iteration (for example), depending on the GUI lag you can tolerate.
function button1_Callback(hObject, eventdata, handles)
% hObject handle to while_button1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
q=0;
while get(hObject,'value')
drawnow
q=q+1
end