writecell writes empty value for the first row in a for-loop
2 次查看(过去 30 天)
显示 更早的评论
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 个评论
dpb
2023-9-20
编辑:dpb
2023-9-20
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...
采纳的回答
Voss
2023-9-20
@Shae Morgan: I think @dpb is exactly right with his comments - the root cause of the problem is that the edit box Value is not updated yet when you try to use it to write to file. In my tests, drawnow doesn't seem to fix it, and I found that presetting a non-empty string in the edit box does indeed cause the string to be written to file on the first iteration (as dpb predicted and contrary to what you observed, strangely).
I also agree with dpb that using the ValueChangedFcn of the edit box is the way to go, rather than relying on the uifigure's CurrentCharacter. The attached app has the structure necessary to do the job as you originally intended/imagined. In my tests, it correctly writes all the information to file.
(Note that I removed the masking/level logic because it wasn't running with the wav files of random data I created for testing, and because that stuff is not relevant to the problem at hand, so you'll have to reintroduce that logic in the right place - in the play_current_sound function, I imagine.)
9 个评论
dpb
2023-9-21
编辑:dpb
2023-9-21
"...Why does pressing enter ("return") trigger the valueChanged function?"
It's how the UI was designed to operate. Nota bene a change of focus by mouse click elsewhere also triggers it.
I do not believe <RETURN> changes focus, but it may, I simply haven't used it enough to know otomh. The uieditfield doc doesn't actually say what the behavior is; you'll have to see what happens.
If you were to use the valueChanging callback, it would generate a callback every keypress of the user which is way more overhead than needed, but essentially the same as your original excepting it is then constrained to be a keystroke actually in the control whereas your original would be anything anywhere in the app figure and the user changing focus other than by the <RETURN> key would not generate the callback for that but would continue to fire for whatever keys did press. That's not the way you intend for the app to be used, but you can't prevent the user from not following instructions precisely either by accident or by trying to break it.
dpb
2023-9-21
编辑:dpb
2023-9-21
"... I'm ... used to javascript/html where if the text exists, then it's rendered and something you can capture."
Capturing from the screen buffer would be something different; you were/are returning the internal state of the control .Value property, that's a different thing than the display buffer. As the ValueChanging callback function describes, there's a background ValueChangingData object that is the buffer holding the user text as being type that you can access/query from the ValueChanging callback function that will look like what's on the screen...but the actual control .Value property itself isn't updated until the user either hits <return> or switches focus away from the control, and then only when the ValueChanged callback executes which is, as noted above, after the figure keystroke callback has completed.
更多回答(0 个)
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Migrate GUIDE Apps 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!