I recently started using R and find myself blocked while trying to build a graphical user interface.
My aim is to code a GUI for the conduction of a survey. Basically, I would like to open a window composed of a question, an answer and a Next button. Upon cliking on Next I wish to save the answer and jump to the next window/question.
As I had problems opening several windows I looked here and found it was possible to open windows one after the other with the help of a handler:
addHandlerChanged() #upon the Next button
So I tried to input a code (see below) for two questions/windows. I thought to save the results in to_return: a matrix 2 rows (1, 2) and 3 columns (Question number, Question, Answer). [I am now trying to write answers question after question in an excel file]
My problem is as follows:
I fail to close the first window after opening the second (I tried adding dispose(h$obj) or visible(win1)=FALSE to the the first windows button handler but it fails)
I fail to "apend" data to my matrix (the to_return matrix is renewed with every window)
# calling GUI library
library(gWidgets)
options(guiToolkit="tcltk")
Q1 <- function(){
# creating first window
win1 <- gwindow("I) Q1.", visible=TRUE)
group <- ggroup(horizontal = FALSE, container=win1)
# creating question
question <- glabel("Do you have a driving license?", container = group)
# creating answer
answer <- gradio(c("Yes","No"), container=group)
# creating next button
nextQuestion <- gbutton("Next",container=group)
# handler
addHandlerChanged(nextQuestion, handler = function(h, ...) {
# answer to save in matrix
to_return <- rbind(to_return,c(svalue(win1),svalue(question),svalue(answer)))
#opening next question
Q2()
print(to_return)
} )
}
Q2<- function(){
# creating second window
win2 <- gwindow("I) Q2.", visible=TRUE)
group <- ggroup(horizontal = FALSE, container=win2)
# creating question
question <- glabel("What is your gender?", container = group)
# creating answer
answer <- gradio(c("Female","Male"), container=group)
# finish button
nextQuestion <- gbutton("Finish",container=group, handler = function(h,...) {
# answer to save in matrix
to_return <- rbind(to_return,c(svalue(win2),svalue(question),svalue(answer)))
print(to_return)
# finish and close
dispose(h$obj)
})
}
If I run Q1() I get the following results where to_return doens't keep the data...
[,1] [,2] [,3]
[1,] "I) Q1." "Do you have a driving license?" "Yes"
[,1] [,2] [,3]
[1,] "I) Q2." "What is your gender?" "Female"
Any help or insight will be greatly appreciated!
Thank you!
Octave
EDIT : Following the answer of jverzani, here is a possible code for two questions with data saving in csv file.
## calling GUI library
library(gWidgets)
options(guiToolkit="tcltk")
setwd("Your\\Path\\Here")
w <- gwindow(title="Survey")
g <- ggroup(cont=w)
state = new.env()
pages <- list()
pages[[1]] = function(cont, state) {
group <- ggroup(horizontal = FALSE, container=cont)
## creating question
question <- glabel("Do you have a driving license?", container = group)
## creating answer
answer <- gradio(c("Yes","No"), container=group)
## creating next button
nextQuestion <- gbutton("Next",container=group)
## handler
addHandlerChanged(nextQuestion, handler = function(h, ...) {
## answer to save in matrix
assign("A", c(svalue(question),svalue(answer)), state)
delete(cont, group)
pages[[2]](cont, state)
})
}
pages[[2]] = function(cont, state) {
group <- ggroup(horizontal = FALSE, container=cont)
## creating question
question <- glabel("What is your gender?", container = group)
## creating answer
answer <- gradio(c("Male","Female", "Other"), container=group)
## creating next button
nextQuestion <- gbutton("Next",container=group)
## handler
addHandlerChanged(nextQuestion, handler = function(h, ...) {
## answer to save in matrix
assign("B", c(svalue(question),svalue(answer)), state)
delete(cont, group)
pages[[3]](cont, state)
})
}
pages[[3]] = function(cont, state) {
group <- ggroup(horizontal=FALSE, container=cont)
## result matrix for csv
to_return=matrix(nrow=0,ncol=2)
colnames(to_return) <- c("Question", "Answer")
for (k in 1:length(names(state))) {
a = get(names(state)[k], state)
to_return <- rbind(to_return,a)
rownames(to_return)[k] <- paste("Q",k,sep = "")
g = ggroup(cont=group, horizontal=TRUE)
glabel(a[1], cont=g)
glabel(" ", cont=g)
glabel(a[2], cont=g)
}
btn <- gbutton("Finish", container=group, handler = function(h,...) {
write.csv(to_return, "survey.csv", row.names=TRUE, col.names=TRUE)
dispose(h$obj)})
}
## start it off
pages[[1]](g, state)
EDIT 2: the line assign("one", c(svalue(question),svalue(answer)), state) should use alphabetical letters ("A", "B"...) or numbers in the right order otherwise answers get mixed up when using for k in names(state).
This isn't the most abstracted, but this pattern using
deleteover new windows, should be easily understood for subsequent modification. The use of an environment helps you keep state between calls to a handler, which won't be the case without some such trick, as assignments will be made within the environment of the handler by default.