2013-06-30 68 views
5

我使用gWidgets在R中製作GUI。直到現在,我一直通過全球環境將價值從一個窗口傳遞到另一個窗口。使用全球環境很容易實現,但並不理想。一個問題是R CMD check抱怨缺少全局變量的可見綁定。使用R引用類在GUI中將值從一個窗口傳遞到另一個窗口

作爲這個問題的解決方案,參考類已被幾個R程序員提到。但要理解參考類在這種情況下如何工作,這將有一個簡單的例子。

讓我給一個愚蠢的圖形用戶界面工作。當用戶點擊第一個窗口的按鈕時,它將模型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) 

如何在本例中使用引用類?

回答

2

調用setRefClass,並將每個小部件和數據值包含爲一個字段。小工具應該有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)) 
} 
+0

很好的例子。代碼會給出警告:在.checkFieldsInMethod(def,fieldNames,allMethods)中: 本地賦值給字段名稱不會改變字段: modelData < - data.frame(x = runif(10),y = runif(10) );可見(win1)< - TRUE; visible(win2)< - TRUE 您的意思是使用「<< - 」? (在類「SillyGui」的初始化方法中) – JacobVanEtten

+1

@JacobVanEtten謝謝。我已經修復了'modelData <-'行。 '可見的<-'行應該是本地分配。如果它使你煩惱,將'setRefClass'的調用封裝在'suppressWarnings'中。 –

+0

謝謝!儘管我會首先關注約翰的建議,但在線提供這個例子真是太棒了。 – JacobVanEtten

2

裏奇的回答是一個辦法。它給了你一個單一的對象(generate_silly_gui返回的實例,你可以使用它來操縱模型用於GUI的窗口小部件,這是一個很好的方法,下面更簡單一些,它僅僅是模型,只是一個小小的偏差,從問題的代碼中使用的引用類下面是使用環境的更加結構化的方式:

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

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

然後,只需在你的代碼並運行model_instance$m更換.GlobalEnv$m

使用參考類允許你做的事情就像添加吸氣劑和吸氣劑一樣,也可以做其他事情,並推動你走向模式l視圖控制器風格。 objectSignals包朝着這個方向發展。

如果您的GUI變得更加複雜,您可能需要將這兩種方法分開。

+0

很好的例子,我會先試試這個,看看'objectSignals'。當使用這種方法時,R CMD CHECK'不會抱怨可見的綁定? – JacobVanEtten

+0

我只是做了一個小測試。我在我的包的.onLoad函數中創建一個引用類的實例,然後在包的函數內使用它。這仍然會產生一個全局綁定問題......當然有一些骯髒的技巧可以避免這個問題:[link](http://stackoverflow.com/questions/8096313/no-visible-binding-for-global-variable-note-在-R-CMD檢查)。但我認爲引用類會使這不必要... – JacobVanEtten

+0

您可以在代碼中創建實例。例如見https://github.com/jverzani/gWidgets2RGtk2/blob/master/R/icons.R#L106 – jverzani

相關問題