writecell writes empty value for the first row in a for-loop
Mostra commenti meno recenti
I have this .mlapp from App Designer, and I'm using it to loop through some audiofiles and then record what the listener heard. The listener types what they hear in the sentence into an edit text input (app.response), and then presses "Enter" to record the answer and advance to the next stimulus. When I look at the excel file at the end, it shows the recorded response, but it's all offset by 1 row and the last response is never recorded. It's like somehow the waitfor isn't working right, and it's saving the response before it collects the information from the edit text.
I feel like this should be really straighforward, but it's taken me hours now to figure out - so I've come to the community. What am I missing? I feel like it's something to do with the "waitfor" and setting the current character, while changing the current character by typing out a response? I can't get it right though.
function BeginButtonPushed(app, event)
%set default character on keyboard to 0 (so we can advance by
%pressing Enter later)
app.UIFigure.CurrentCharacter = char(0);
%access stimuli
task = 'Type_babble_1'; %Set task name
stim_dir=[cd '\stimuli']; %set directory for stimuli
FileList = dir(fullfile(stim_dir,'*.wav')); %create list of stimuli
%loop that controls stimulus playback
for i=1:length(FileList)
app.Counter.Value = length(FileList)+1-i; %adding a number for the counter
%load the signal
signalpath = [stim_dir '\' FileList(play_order(i)).name];
[fnames,fs]=audioread(signalpath);
%present stimulus
duration = length(fnames)/fs;
sound(fnames,fs);
pause(duration)
%wait to collect response
app.UIFigure.CurrentCharacter = char(0);
waitfor(app.UIFigure,'CurrentCharacter', char(13))
app.UIFigure.CurrentCharacter = char(0);
%collect trial information and write it to the file.
sentence_code=FileList(play_order(i)).name;
output = [cellstr(app.ID.Value) cellstr(task) cellstr(sentence_code) cellstr(app.response.Value)];
disp(output)
writecell(output,[app.ID.Value '-' task '-data.xlsx'],"Sheet",1,'WriteMode','append');
end
fclose('all');
msgbox('You''re done!')
end
14 Commenti
Mario Malic
il 20 Set 2023
I think it is because char(0) is NULL, set your CurrentCharacter property like below and try
app.UIFigure.CurrentCharacter = '';
Shae Morgan
il 20 Set 2023
Mario Malic
il 20 Set 2023
Modificato: Mario Malic
il 20 Set 2023
Maybe this as well: app.Counter.Value = length(FileList)+1-i
You didn't show how do you obtain the app.ID.Value.
Debugging is also helpful and can help you track the issue.
Shae Morgan
il 20 Set 2023
Mario Malic
il 20 Set 2023
I see now, it is impossible for CurrentCharacter to have no value.
Just an idea to test, I don't want to make an app now to test things. Maybe the second line appends the NULL to the edit field which is being currently edited.
waitfor(app.UIFigure,'CurrentCharacter', char(13))
% app.UIFigure.CurrentCharacter = char(0);
app.UIFigure.CurrentCharacter = '+';
Shae Morgan
il 20 Set 2023
Mario Malic
il 20 Set 2023
If possible, a minimal reproducible example would be great.
It doesn't make any sense to me that Response is shifted by a single row.
I would suggest to inspect ASCII values of app.response.Value, maybe it contains some leftovers of 0, 10, 13?
double(app.response.Value)
waitfor doc says the object "can be the child of a Figure object created with the figure or uifigure function, or it can be the child of a container in a Figure object."
It doesn't say anything about it being the UIFigure object itself.
It appears the content of the edit text control isn't actually updated when your code is checking it -- I don't know if a drawnow would cause a pending internal callback to be executed or not; I've never tried to mess at such a low level with gui inputs. If that doesn't solve it, you'll have to figure out just what it does take to get the content of the edit field actually updated/refreshed internally to the content on the screen before reading it. I'd wonder about stuffing that (0) into the current key buffer immediately, certainly.
I'd wager (at least a cup of coffee, if not the house) that if you preset the content of the response text edit field to some initial dummy value you'll see that come up in the first cell that would essentially prove the hypothesis.
ADDENDUM: Further rambling wonderings/musings...
a. Wonder if stuffing the char(0) is generating the first CR internally, maybe, before the user even gets to the edit field?
b. Continuation of the first --the object response you're wanting to wait on would be in the text edit field itself; the way it's coded, anywhere while the figure has focus would be good enough.
c. Use the <value changed> callback function for the edit text box itself instead -- it is only called when the user either hits <return> or switches focus away (and in use you can't prevent the user from doing so in which case the "13" will not necessarily ever happen. I'd have to dig into the overal functionality to see how to structure it to use it instead of messing with the current, but I think it's not the right way (as you're finding in trying to get it to work as desired).
d. A <value changing> callback function instead would give you access every keystroke as well as for the <return> for change of focus; just ignore anything until the magic end...
Not the issue, but
signalpath = [stim_dir '\' FileList(play_order(i)).name];
should be
signalpath=fullfile(FileList(play_order(i)).folder,FileList(play_order(i)).name);
You did well in using fullfile() earlier, but fell into the string construction trap later...
Shae Morgan
il 20 Set 2023
Shae Morgan
il 20 Set 2023
Did you try inserting a drawnow first after the waitfor to see if that would update the field?
Stuffing a character into the buffer isn't the same as initializing the edit field content first so I'm not sure you actually did initialize the content of the edit field. If it were a default property on initialization and then still showed up as empty it would indicate somewhere your code wiped that field out before the loop which would then also coincide with getting the content the next pass.
One possible kludge -- test the length of the returned field -- if it is zero-length, then just continue the loop -- although you would then probably have to execute the loop N+1 times instead of N.
I still think the real solution will be to use the callback function for the text field object itself instead; this just seems excessively complex besides the issue of what if the user doesn't follow directions and leaves the control instead of hitting <return>.
OBTW, you can attach zip file that would have needed data...I, for one, would have to do quite a bit of work to get any wav files handy; I simply don't use them in anything I ever do so there aren't any just laying around where I know where they are...although I know there's a whole repository of stuff MS loads, I have no idea about where. Make it simple...
A minimal example would just loop picking up user response; wouldn't even have to play anything...
Shae Morgan
il 20 Set 2023
Risposta accettata
Più risposte (0)
Categorie
Scopri di più su Creating, Deleting, and Querying Graphics Objects in Centro assistenza e File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!
