Failing to manage multiple windows and save data in a survey's GUI with R and gWidgets

41 Views Asked by At

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:

  1. 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)

  2. 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).

1

There are 1 best solutions below

2
jverzani On

This isn't the most abstracted, but this pattern using delete over 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.

# calling GUI library
library(gWidgets2)
options(guiToolkit="tcltk")


w <- gwindow()
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("one", 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("two", c(svalue(question),svalue(answer)), state)
        delete(cont, group)
        pages[[3]](cont, state)
    })
}

pages[[3]] = function(cont, state) {
    group <- ggroup(horizontal=FALSE, container=cont)
    for (k in names(state)) {
        g = ggroup(cont=group, horizontal=TRUE)
        a = get(k, state)
        glabel(a[1], cont=g)
        glabel(" ", cont=g)
        glabel(a[2], cont=g)
    }
}

## start it off
pages[[1]](g, state)