MATLAB Answers

app designer input from spreadsheet and output to spreadsheet

4 views (last 30 days)
frankenberry
frankenberry on 30 Mar 2020
Answered: frankenberry on 14 Apr 2020
The code below works for one spreadsheet from an excel workbook. I need it to work for 5 or more sheets in the same workbook. I realize this will likely be a "for loop" in the "% Selection changed function: ButtonGroup". I'm unsure where to put the loop. I think it needs to occur before the "if statement" and should end before
app.QuestionTextArea.Value = 'Questionnaire Complete! Click <Next> to continue.'; %indicates the end of the first questionnaire
Specifically, if I wanted to add:
num_sheets = length(sheetnames('Questionnaires.xlsx')); %number of sheets in Questionnaires.xlsx
for sheetcount = 1:1:length(num_sheets) %sheet counter for number of sheets
before the [app.CurrentCount = app.CurrentCount + 1;], where would I reference the variable sheetcount within the code below? Should sheetcount be a "for loop"?
The app is also using dynamic radio buttons which are coded in the startupFcn(app) and after the 'else statement' in the "% Selection changed function: ButtonGroup". If you need more information, please let me know. Helpful answers are appreciated.
% Code that executes after component creation
function startupFcn(app)
% Specify initial values when the app starts up; initialize values; set defaults
get(groot,'Screensize');
drawnow;
app.UIFigure.WindowState = 'maximized';
%app.Questions = readtable('Questionnaires.xlsx', 'NumHeaderLines', 0);
app.Questions = readtable('Questionnaires.xlsx',"ReadVariableNames",false,"TextType","string");
app.NumberOfQuestions = height(app.Questions);
app.Instructions = readtable('Questionnaires.xlsx',"ReadVariableNames",false,"TextType","string","Range","A1");
app.NumberOfInstructions = height(app.Instructions);
app.Columns = 1:1:width(app.Instructions);
app.Columns = 3:2:width(app.Questions);
app.QuestionTextArea.Value = app.Questions{app.CurrentCount,2};
app.InstructionsTextArea.Value = app.Instructions{app.CurrentCount,1};
Position = [10 50 90 25];
for columnNumber = app.Columns
option = app.Questions{app.CurrentCount, columnNumber};
if(~strcmp(option,""))
r = uiradiobutton(app.ButtonGroup,'Text', option, "FontSize",26);
if (columnNumber ~= 2)
Position(1) = Position(1) + 100;
end
r.Position = Position;
end
end
Position(1) = Position(1) + 100;
app.DummyButton = uiradiobutton(app.ButtonGroup, 'Visible',"off", 'Value', 1, 'Position', Position, 'Text', 'Dummy', 'FontSize', 26);
app.filenm.Question = zeros(0);
app.filenm.Answer = zeros(0);
end
.....
% Selection changed function: ButtonGroup
function ButtonGroupSelectionChanged(app, event)
selectedButton = app.ButtonGroup.SelectedObject;
app.CurrentCount = app.CurrentCount + 1;
newRow = {app.QuestionTextArea.Value{1}, selectedButton.Text};
app.Answers = [app.Answers; newRow];
if(app.CurrentCount > app.NumberOfQuestions)
writetable(app.Answers, 'Answers.xls');
writetable(app.Answers, app.filenm);
app.QuestionTextArea.Value = 'Questionnaire Complete! Click <Next> to continue.'; %indicates the end of the questionnaire
app.ButtonGroup.Visible = 'off';
else
while size(app.ButtonGroup.Children, 1) > 1
button = app.ButtonGroup.Children(end);
if(~strcmp(button.Text,'Dummy'))
button.Parent = [];
else
button = app.ButtonGroup.Children(end - 1);
button.Parent = [];
end
end
app.QuestionTextArea.Value = app.Questions{app.CurrentCount,2};
Position = [10 50 90 25];
for columnNumber = app.Columns
option = app.Questions{app.CurrentCount, columnNumber};
if(~strcmp(option,""))
r = uiradiobutton(app.ButtonGroup,'Text', option,"FontSize",26);
if (columnNumber ~= 2)
Position(1) = Position(1) + 100;
end
r.Position = Position;
end
end
app.ButtonGroup.SelectedObject = app.DummyButton;
end
end

  2 Comments

Guillaume
Guillaume on 4 Apr 2020
Is this correct?
app.Questions = readtable('Questionnaires.xlsx', ..
app.NumberOfQuestions = height(app.Questions);
app.Instructions = readtable('Questionnaires.xlsx', ..
app.NumberOfInstructions = height(app.Instructions);
You're reading twice the same thing?
Then you have
app.Columns = 1:1:width(app.Instructions);
app.Columns = 3:2:width(app.Questions);
The first of the two is obviously pointless.
SImilarly, in your callback, you have two consecutive writetable of the same table.
As for your question: "I need it to work for 5 or more spreadsheets"
Which part is "it"? I think you need to describe a bit more. If I understood your code displays a question and a selection of answers as radio button. Each time, a question is answered it moves onto the next question until all questions have been answered. The list of question comes from one spreadsheet. What would the workflow be if there are several worksheet of questions?
frankenberry
frankenberry on 4 Apr 2020
Unless I "readtable" for each property, the app will not work. I realize it looks odd. The 'height" command will not work unless I do it this way (i.e., the 'height' command will only work for the first app.property and not the second app.property if readtable is not input again).
I realize the first app.Columns looks weird. This code will be used for other experiments which may have different instructions. In which case, they will need to have this variable to adjust for their experiments.
The two writetables serve different purposes. The first writes the data collected from all clients, the second writes to the client's file on the drive.
I need a loop for spreadsheets that will run through the code. I'm unsure where to reference the variable sheet_count, if I add that or if that is the correct code to add.
The workbook contains several worksheets. Each worksheet is a different questionnaire with different possible responses (hence, the dynamic buttons). You seem to understand how it works pretty well. Once the first list of questions is completed, the code should call the next sheet and present the next list of questions. The possible responses will change automatically to suit that questionnaire. So the code needs to go to the next sheet before it reaches these lines (i.e. after it has written out the data to the client's file for the first questionnaire):
app.QuestionTextArea.Value = 'Questionnaire Complete! Click <Next> to continue.'; %indicates the end of the questionnaire
app.ButtonGroup.Visible = 'off';
Does this help answer your questions?

Sign in to comment.

Accepted Answer

frankenberry
frankenberry on 14 Apr 2020
This works!
% Selection changed function: ButtonGroup
function ButtonGroupSelectionChanged(app, event)
selectedButton = app.ButtonGroup.SelectedObject;
% Presents Questions 1 Sheet at a Time
% Collects answers
app.CurrentCount = app.CurrentCount + 1; % question counter
newRow = {app.QuestionTextArea.Value{1}, selectedButton.Text};
app.Answers = [app.Answers; newRow]; % inserts new row in answer 'file'
% presents questions until current count reached then writes values to backup and client file
if(app.CurrentCount > app.NumberOfQuestions) % if the question counter is greater than the number of questions
writetable(app.Answers, 'Answers.xlsx', 'Sheet', app.sheet_counter); %'WriteMode', 'Append'); % write the values to the table Answers.xlsx as a backup - should be all questions from all sheets to one page
writetable(app.Answers, app.filenm, 'Sheet', app.sheet_counter); % write the answers to the client's excel file; ***I need to get it to write to the correct sheet
% read questions from next sheet if that sheet exists
if app.sheet_counter < app.num_sheets
app.Answers = table;
app.CurrentCount = 1;
app.sheet_counter = app.sheet_counter + 1;
app.Questions = readtable('Questionnaires.xlsx',"ReadVariableNames",false,"TextType","string","Sheet", app.sheet_counter); % Succeeds because the sheet counter is a scalar
app.NumberOfQuestions = height(app.Questions); % total number of questions
app.Instructions = readtable('Questionnaires.xlsx',"ReadVariableNames",false,"TextType","string","Range","A1", "Sheet", app.sheet_counter); %height will not work unless readtable comes first; % Succeeds because the sheet counter is a scalar
app.NumberOfInstructions = height(app.Instructions); % total number of instructions; just in case future projects require more rows for instructions;
app.Columns = 3:2:width(app.Questions); % gets the toals number of responses
app.QuestionTextArea.Value = app.Questions{app.CurrentCount,2}; % writes the question in the front panel box from the row count and column 2
app.InstructionsTextArea.Value = app.Instructions{app.CurrentCount,1}; % writes the instruction in the front panel box from the row count and column 1
else
app.QuestionTextArea.Value = 'Questionnaire Complete! Click <Next> to continue.'; %***The problem begins here; indicates the end of the questionnaire
app.ButtonGroup.Visible = 'off'; % turns button group off
return;
end
end
% the following sections creates the button fields and then text and shows them in the ButtonGroupSelection field
while size(app.ButtonGroup.Children, 1) > 1
button = app.ButtonGroup.Children(end);
if(~strcmp(button.Text,'Dummy'))
button.Parent = [];
else
button = app.ButtonGroup.Children(end - 1);
button.Parent = [];
end
end
app.QuestionTextArea.Value = app.Questions{app.CurrentCount,2};
Position = [1 50 160 100];
for columnNumber = app.Columns
option = app.Questions{app.CurrentCount, columnNumber};
if(~strcmp(option,"") && ~ismissing(option))
r = uiradiobutton(app.ButtonGroup,'Text', option,"FontSize",26);
if (columnNumber ~= 1)
Position(1) = Position(1) + 160;
end
r.Position = Position;
end
end
app.ButtonGroup.SelectedObject = app.DummyButton;
end

  0 Comments

Sign in to comment.

More Answers (0)

Sign in to answer this question.


Translated by