My program is a question/answer task:
-participant must press on space (keyboard) bar to play a sound
-participant must after that press on one of the two button (mouse)
-participant must press on space bar to play a sound
...
The problem is, I want to allow only one press on space bar, because user can press many time on space and play the sound x times.
How to block the figure1_KeyPressFcn while waiting the mouse response, and once we have the mouse response we reactivate the function ?
function figure1_KeyPressFcn(hObject, eventdata, handles)
switch eventdata.Key
case 'space'
%% processing x task
%playing sounds 1000 ms
soundsc(y,Fs);
guidata(hObject, handles); %%// Save handles data
otherwise
disp('error');
end
end
function pushbutton1_Callback(hObject, eventdata, handles)
%processing task
guidata(hObject, handles); %%// Save the handles data
end
function pushbutton2_Callback(hObject, eventdata, handles)
%processing task
guidata(hObject, handles); %%// Save the handles data
end
You could use a global flag, something like this:
global clicked;
clicked = true;
Then, on your figure1_KeyPressFcn function, you only call the switch if the user has clicked, like this:
global clicked;
if clicked
switch eventdata.Key
case 'space'
clicked = false;
%% processing x task
...
end
end
And on both your pushbutton?_Callback's, you add this:
global clicked;
clicked = true;
To set clicked to true and allow figure1_KeyPressFcn to process space keys again.
Related
Suppose I have two pushbuttons on MATLAB GUI. When I press on pushMain, I want to call the callback of pushChild button.
I might have put simply pushChild_Callback(hObjects, eventdata, handles) in the pushMain's callback but my problem is I created pushChild object by code so there is no seperate callback function on the code.
handles.pushChild = uicontrol('Style','pushbutton');
handles.pushChild.Callback = {#printA, 1}
% this means when I press on pushChild button, it will print "A = 1"
function printA(src, event, j)
handles = guidata(src);
fprintf('A = %d\n',j);
Now when I pressed on pushMain, I want to see "A = 1" on the screen.
I tried:
function pushMain(hObject, eventdata, handles)
fprintf('1\n');
fprintf('2\n');
fprintf('3\n');
handles.pushChild.Callback(); % option 1 -> no error but nothing happens.
handles.pushChild.Callback(hObject, eventdata, handles) % option 2 -> nothing happens
Regards.
What's the best practice in the following scenario:
I have loop that starts upon button press and during execution the iterations should respond to inputs through the GUI (e.g. slider value change). This is not possible in an uninterruptible loop so therefore, a working but clumsy solution is to use a pause such that:
while true
get(handles.slider1,'value')
pause(0.5)
end
Are there alternative, more elegant solutions to this problem?
Edit: as clarification, a variant that does NOT work (i.e. does not output changing slider values):
while true
get(handles.slider1,'value')
end
You can update the slider value to a global variable.
function slider1_Callback(hObject, eventdata, handles)
global SliderValue;
SliderValue = hObject.Value;
Then access SliderValue from any function.
function pushbutton1_Callback(hObject, eventdata, handles)
global SliderValue;
while a<100
a = SliderValue + a;
end
I created an interface which automatically reads in data through the serial port, hence the reason I implemented the BytesAvailableFcn Callback
handles.fileID.BytesAvailableFcnMode = 'terminator';
handles.fileID.BytesAvailableFcn = {#streamData_fastTrak, handles};
The data that is read is displayed in a table chosen by the user (through use of radio buttons in the GUI). When an option is chosen a callback occurs to save the selected radio button to a variable which is saved in the handles struct. I have followed the program step for step and I am sure this callback does occur and that the variable is saved. However when the serial callback occurs the handles struct still has the old option value.
Here is the serial callback code:
function handles = streamData_fastTrak(hObject, eventdata, handles)
handles.num = handles.num + 1;
%receive data through serial
line = transpose(fscanf(handles.fileID, ' %f ' ));
table_data = get(handles.uitable1, 'data');
table_data_style = get(handles.uitable4, 'data');
display(handles.butt_state);
display(handles.num);
if(fix(line(1)) == 1 && strcmp(handles.butt_state, 'style_button'))
table_data_style(handles.select_Indices(1), 2:(length(line)+1)) = num2cell(line);
set(handles.uitable4, 'data', table_data_style);
display(handles.select_Indices);
elseif(fix(line(1)) > 1 && strcmp(handles.butt_state, 'stat_button'))
table_data(line(1)-1, 1:length(line)) = num2cell(line);
set(handles.uitable1, 'data', table_data);
if(line(1) == countStates(handles))
streamSensor_1_2_3(hObject, handles);
handles.time_step = handles.time_step + 1;
end
end
And the radio button callback:
function uipanel2_SelectionChangeFcn(hObject, eventdata, handles)
handles.butt_state = get(get(handles.uipanel2,'SelectedObject'), 'tag');
display(handles.butt_state);
guidata(hObject, handles);
The way I see it there are 2 ways to approach the problem:
The first way (I don't recommend this as much as the second one) is to pass the data you want updates to a string control and have it read back by your serial port function.
The other way that i recommend is to include a dummy button with a call back that calls
handles.fileID.BytesAvailableFcn = {#streamData_fastTrak, handles};
Again - this will update the new "handles" data to the callback function
For example
Assuming a dummy push button with tag PB1
function handles = streamData_fastTrak(hObject, eventdata, handles)
%% do stuff here
%% update handles data
PB1_Callback (handles.PB1,event,dat)
guidata(handles.PB1,handles) %% function ends
%% dummy button callback function%%
function PB1_Callback(hObject,event,handles)
handles.fileID.BytesAvailableFcn = {#streamData_fastTrak, handles};
guidata(hObject,handles) %% dummy button function ends
You can make the dummy button invisible by making the background color of the button same as that of the UI.
When you first declare your callback function for the ByteAvailableFcn in the line:
handles.fileID.BytesAvailableFcn = {#streamData_fastTrak, handles};
Matlab assign the function handle to the event and also pass the handles stucture at this point of time. This is now frozen into the private workspace of the callback. If you change the handles structure later on in your code (as you do when you try to attach the variable handles.butt_state), the callback doesn't know it, it still use the handles structure that was passed when you declared the callback.
There are several ways of getting this value correctly but I'll give 2 of them:
1) get the value from the radio button when needed
in your streamData_fastTrak callback function, query the button state directly from the uicontrol (instead of checking for a saved value)
handles.butt_state = get(get(handles.uipanel2,'SelectedObject'), 'tag');
This way you are sure to get the latest state of the radio button.
2) Store value in appdata
Every time the button state is changed, store the value somewhere, but you still have to query this value when your callback want to execute. A good place to save values are in the appdata (accessed using setappdata and getappdata).
So in your button callback:
function uipanel2_SelectionChangeFcn(hObject, eventdata, handles)
butt_state = get(get(handles.uipanel2,'SelectedObject'), 'tag');
setappdata(handles.uipanel2, 'butt_state' , butt_state );
display(butt_state);
And in your streamData_fastTrak callback:
function handles = streamData_fastTrak(hObject, eventdata, handles)
butt_state = getappdata(handles.uipanel2, 'butt_state' );
%// and the rest of your code ...
Initially my prog is like that (playing sound and judge what kind of sound is) :
n_repetition=10
for i=1:n_repetition
playsound(strcat(i,'wav'));
answer=input(' answer q/z/e ?','s');
switch answer
case 'q'
asw="bird";
case 'z'
asw="water";
case 'e'
asw="wind";
otherwise
disp('error');
end
end
Now I'm trying to make it more interactive with GUI, I'm using GUIDE and i've generate a .fig which contain 4 buttons: OK button, BIRD, WATER, WIND
I've also my callbacks which are empty now
What I want to do is:
-Initially all buttons are inactive
-Participant should press on ok to begin
-play sounds
-activate the buttons (sound bird, water, wind)
-catch response
-deactivate button
-wait for press ok for new trial
How could I adapt my initial code the the callback, where should I put my loop ? Thanks
Add these at the start of guiname__OpeningFcn -
handles.song_count = 0;
handles.asw = cell(10,1);
Edit your button callbacks to these -
% --- Executes on button press in ok_button.
function ok_button_Callback(hObject, eventdata, handles)
handles.song_count = handles.song_count +1;
filename = strcat(num2str(handles.song_count),'.wav');
[y,~] = audioread(filename);
%%// Use soundsc or your custom playsound function to play the sounds
soundsc(y); %playsound(strcat(i,'wav'));
guidata(hObject, handles); %%// Save handles data
return;
% --- Executes on button press in bird_button.
function bird_button_Callback(hObject, eventdata, handles)
asw = 'bird'; %%// Do something with 'asw'
handles.asw(handles.song_count) = {asw}; %%// Store the 'asw' values as a cell array
guidata(hObject, handles); %%// Save the handles data
return;
% --- Executes on button press in water_button.
function water_button_Callback(hObject, eventdata, handles)
asw = 'water'; %%// Do something with 'asw'
handles.asw(handles.song_count) = {asw}; %%// Store the 'asw' values as a cell array
guidata(hObject, handles); %%// Save the handles data
return;
% --- Executes on button press in wind_button.
function wind_button_Callback(hObject, eventdata, handles)
asw = 'wind'; %%// Do something with 'asw'
handles.asw(handles.song_count) = {asw}; %%// Store the 'asw' values as a cell array
guidata(hObject, handles); %%// Save the handles data
return;
Note: At any point of time view handles.asw to look at the button clicks history.
Suggestion: If it's okay to show the choices made by the GUI user as a list, you might consider adding a Table into the GUI. You can put the data from handles.asw into such a Table.
How to get the value of a uicomponent slider on Matlab when a key is pressed?
I'm using this in the GUI code:
% --- Executes just before teste is made visible.
function teste_OpeningFcn(hObject, eventdata, handles, varargin)
% Choose default command line output for teste
handles.output = hObject;
handles.slid=uicomponent('style','slider',0,9,5,'position',[10 30 200 50]);
set(handles.slid, 'KeyPressedCallback','handles.slid.value');
% Update handles structure
guidata(hObject, handles)
The slider works correctly, but when I press a key, this returns the error "Undefined variable "handles" or class "handles.slid.value".
How to solve?
You can connect a callback to the desired event and get the value there from the src parameter
handles.slid=uicomponent('style','slider',0,9,5,'position',[10 30 200 50]);
set(handles.slid, 'KeyPressedCallback','sliderCallback');
function sliderCallback(src,evt)
display(['slider state ' num2str(get(src, 'Value'))]);
end
If the sliderCallback function is not accessible globally, you can instead set it through function pointer:
set(handles.slid, 'KeyPressedCallback',#sliderCallback);