5

我正在使用 gWidgets 在 R 中制作 GUI。到目前为止,我一直在通过全局环境将值从一个窗口传递到另一个窗口。使用全局环境实现起来很简单,但并不理想。一个问题是R CMD check抱怨缺少全局变量的可见绑定。

作为这个问题的解决方案,一些 R 程序员已经提到了引用类。但是要理解引用类在这种情况下是如何工作的,举一个简单的例子真的很有帮助。

让我给一个愚蠢的 GUI 来使用。当用户点击第一个窗口的按钮时,它会将模型m置于全局环境中。第二个按钮m从全局环境中获取并给出输出。当您再次点击第一个按钮时,它将创建一个新模型m并更改第二个按钮的输出。如果关闭第一个窗口,第二个窗口中的按钮仍然可以工作,因为m是在全局环境中。

library(gWidgets)
options(guiToolkit = "tcltk")

h1 <- function(h, ...){
  d1 <- data.frame(x=runif(10), y=runif(10))
  .GlobalEnv$m <- lm(x ~ y, data=d1)
}

g1 <- gbutton("1. Make model", 
  container=gwindow(), handler=h1)

h2 <- function(h, ...){
  d2 <- data.frame(y=(1:10)/10)
  p <- predict(.GlobalEnv$m, newdata=d2)
  print(p)
}

g2 <- gbutton("2. Make prediction", 
  container=gwindow(), handler=h2)

在此示例中如何使用引用类?

4

2 回答 2

2

里奇的回答是一种方法。它为您提供了一个对象(由该对象返回的实例generate_silly_gui,您可以使用它来操作模型用于 GUI 的小部件。一个很好的方法。下面更简单,它只是做模型,只是与代码略有偏差在问题中。这里使用引用类是使用环境的更有条理的方式:

OurModel <- setRefClass("OurModel",
                       fields="m")

## a global
model_instance = OurModel$new(m=NULL)

然后只需在您的代码中替换.GlobalEnv$mmodel_instance$m运行。

使用引用类可以让你做一些事情,比如添加 getter 和 setter,它们也可以做其他事情,并将你推向 model-view-controller 风格。objectSignals包裹朝着那个方向发展。

如果您的 GUI 变得更复杂,您可能希望将这两种方法分离。

于 2013-07-01T14:37:28.313 回答
2

调用setRefClass,并将每个小部件和数据值包含为一个字段。小部件应该有 type ANY。在方法中初始化这些小部件initialize,并将功能外包给其他方法。创建一个函数来包装类的创建。

silly_gui_generator <- setRefClass(
  "SillyGui",
  fields = list(
    #widgets
    win1           = "ANY",
    win2           = "ANY",
    button1        = "ANY",
    button2        = "ANY",
    #data
    modelData      = "data.frame",
    predictionData = "data.frame",
    model          = "lm"
  ),
  methods = list(
    initialize = function(modelData = NULL)
    {
      if(is.null(modelData))
      {
        modelData <<- data.frame(x = runif(10), y = runif(10))
      }

      win1 <<- gwindow(visible = FALSE)
      win2 <<- gwindow(visible = FALSE)
      button1 <<- gbutton(
        "1. Make model", 
        container = win1, 
        handler   = function(h, ...)
        {          
          makeModel()
        }
      )
      button2 <<- gbutton(
        "2. Make prediction", 
        container = win2, 
        handler   = function(h, ...)
        {          
          print(predictModel())
        }
      )
      visible(win1) <- TRUE
      visible(win2) <- TRUE
    },
    makeModel = function()
    {
      model <<- lm(x ~ y, data = modelData)
    },
    predictModel = function()
    {
      predictionData <<- data.frame(y = (1:10) / 10)
      predict(model, newdata = predictionData)
    }
  )
)

generate_silly_gui <- function(modelData = NULL)
{
  invisible(silly_gui_generator$new(modelData = modelData))
}
于 2013-07-01T10:09:18.917 回答