Невозможность управления несколькими окнами и сохранения данных в графическом интерфейсе опроса с помощью R и gWidgets

Недавно я начал использовать R и обнаружил, что меня заблокировали при попытке создать графический интерфейс пользователя.

Моя цель — написать графический интерфейс для проведения опроса. По сути, я хотел бы открыть окно, состоящее из вопроса, ответа и кнопки Далее. После нажатия Далее я хочу сохранить ответ и перейти к следующему окну/вопросу.


Поскольку у меня были проблемы с открытием нескольких окон, я посмотрел здесь и нашел можно было открывать окна одно за другим с помощью обработчика:

addHandlerChanged() #upon the Next button

Поэтому я попытался ввести код (см. Ниже) для двух вопросов/окон. Думал сохранить результаты в to_return: матрица 2 строки (1, 2) и 3 столбца (Номер вопроса, Вопрос, Ответ). [Сейчас я пытаюсь написать ответы на вопрос за вопросом в файле Excel]

Моя проблема заключается в следующем:

  1. Мне не удается закрыть первое окно после открытия второго (я пытался добавить dispose(h$obj) или visible(win1)=FALSE в первый обработчик кнопки Windows, но он терпит неудачу)

  2. Мне не удается "присоединить" данные к моей матрице (матрица to_return обновляется с каждым окном)

# 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)
  })
}

Если я запускаю Q1(), я получаю следующие результаты, где to_return не сохраняет данные...

     [,1]     [,2]                             [,3] 
[1,] "I) Q1." "Do you have a driving license?" "Yes"
     [,1]     [,2]                   [,3]    
[1,] "I) Q2." "What is your gender?" "Female"

Любая помощь или понимание будет принята с благодарностью!

Спасибо!

Октава


РЕДАКТИРОВАТЬ: после ответа jverzani, вот возможный код для двух вопросов с сохранением данных в файле csv.

## 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)

РЕДАКТИРОВАТЬ 2: строка assign("one", c(svalue(question),svalue(answer)), state) должна использовать буквы алфавита ("A", "B"...) или цифры в правильном порядке, в противном случае ответы запутаться при использовании for k в именах (состоянии).


person Octave J    schedule 12.09.2018    source источник


Ответы (1)


Это не самая абстракция, но этот шаблон с использованием delete поверх новых окон должен быть легко понятен для последующей модификации. Использование среды помогает вам сохранять состояние между вызовами обработчика, чего не будет без такого трюка, поскольку по умолчанию назначения будут выполняться в среде обработчика.

# 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)
person jverzani    schedule 12.09.2018
comment
Спасибо за ваш ответ ! Все работает, и я постараюсь глубже изучить функции new.environment() и handler(), чтобы понять, как все происходит. Если я правильно понимаю, здесь мы создаем только одно окно и обновляем показанные в этом окне группы? Однако, когда я пытаюсь ввести размер в предварительном окне w, это не влияет на способ отображения окон после этого... Размер пересчитывается для каждой группы, отображаемой в окне? - person Octave J; 13.09.2018
comment
Это зависит от инструментария. Я забыл о tcltk. Но вам может понадобиться назвать размер. Это не обязательно для вашей проблемы, но я не фанат новых окон, поэтому добавил это. - person jverzani; 14.09.2018