8

Rパッケージ用のGUIを(gWidgetsを使用して)開発しようとしています。私の計画は、データを保持し、関数ごとに小さなGUIラッパーを呼び出すボタンを備えたメインウィンドウを構築することでした。残念ながら、私は基本的な(?)問題で立ち往生しています-データを転送する方法がわかりません。

質問:

  • 別々のウィンドウ間でデータを適切に送信するにはどうすればよいですか?
  • 別のウィンドウのハンドラー内からデータを送信するにはどうすればよいですか?

私の問題は次のような ものです。gWidgetsを使用してRに変数をロードおよび保存しますが、私が読んだことから、.GlobalEnvの使用はお勧めしません。

また、<<-演算子を使用している人を見たことがあります:http://www.mail-archive.com/r-sig-gui@r-project.org/msg00053.html、しかし私はそれを正しく再現することができません(そして私の例ではうまくいきません)。

以下は簡単な例です。ここでは、テキストを別のウィンドウに送信し、ボタンが押された場合に再度送信しようとしています。ハンドラー内でreturnを試してみましたが、機能しません(許可されているかどうかもわかりません)。サブウィンドウは、ハンドラー/内部関数がデータに作用する前に、関数の最後ですぐにその値を返します。ハンドラーからメインウィンドウにアクセスする方法がわかりません。

main <- function(){

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

  w <- gwindow(title="Main window",
               visible=FALSE)

  txt <- gtext(text="Initial text in main window.",
               container=w)

  btn <- gbutton("Send to sub window", container=w)

  addHandlerChanged(btn, handler = function(h, ...) {
    shouldbenew <- subwindow(svalue(txt))
    svalue(txt) <- paste("The sub window immediately returns 'TRUE', before pushing 'Return to main':", shouldbenew )
  } )

  visible(w) <- TRUE

}

subwindow<- function(text){

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

  sw <- gwindow(title="Sub window",
                visible=FALSE)

  editedtxt <- gtext(text=paste(text, "- Text is transferred to the sub window, but I don't know how to send it back to the main window"),
                     container=sw)

  btn <- gbutton("Send to main window", container=sw)

  addHandlerChanged(btn, handler = function(h, ...) {
    newtxt <- svalue(editedtxt)
    return(newtxt)

  } )

  visible(sw) <- TRUE

}

更新: 上記の例を使用して説明した、(jverzaniによって提案された)前進の方法として私が選んだ解決策は次のとおりです。提案された解決策を正しく理解し、それを「素晴らしい」方法で実装し、理想的にはCRANで受け入れられたことを願っています。

要約すると、メインウィンドウ環境内に新しい環境を作成しました。サブウィンドウを編集して、呼び出しの環境を取得しました。サブウィンドウのボタンを押すと、assign編集されたテキストが渡された環境に送られます。サブウィンドウを閉じてメインウィンドウにフォーカスを合わせると、編集したテキストに環境から。を使用してアクセスできますget

main <- function(){

  library(gWidgets)
  options(guiToolkit="RGtk2")
  # Create a new environment for passing data.
  .mainGlobal <- new.env()

  w <- gwindow(title="Main window", visible=FALSE)

  txt <- gtext(text="Initial text in main window.",
               container=w)

  btn <- gbutton("Send to sub window", container=w)

  addHandlerChanged(btn, handler = function(h, ...) {
    # Call sub widget passing text and environment.
    subwindow(text=svalue(txt), env=.mainGlobal)
  } )

  visible(w) <- TRUE

  addHandlerFocus(w, handler = function (h, ...) {

    if(exists("myText", envir=.mainGlobal)){
      # Retrieve text and update.
      svalue(txt) <- get("myText", envir=.mainGlobal)
    }    
  })

}

subwindow<- function(text, env=NULL){

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

  sw <- gwindow(title="Sub window", visible=FALSE)

  editedtxt <- gtext(text=text, container=sw)

  btn <- gbutton("Send to main window", container=sw)

  addHandlerChanged(btn, handler = function(h, ...) {
    newtxt <- svalue(editedtxt)
    assign("myText", newtxt, envir=env)
  } )

  visible(sw) <- TRUE

}
4

3 に答える 3

5

より良いアプローチですが、コードの大幅なやり直しが必要なアプローチは、GUIを参照クラスに格納することです。

setRefClassフィールドのリスト(ウィジェットごとに1つ)を使用して呼び出し、GUIが作成される初期化メソッドを定義します。私は通常、インスタンスを作成する呼び出しをラップする関数を作成します。setRefClassコードブロックの最後を参照してください。

mainGui <- suppressWarnings(setRefClass( #Warnings about local assignment not relevant 
  "mainGui",
  fields = list(
    #widgets
    w   = "ANY",       #"GWindow"
    txt = "ANY",       #"GEdit"
    btn = "ANY"        #"GButton"
  ),
  methods = list(
    initialize = function(windowPosition = c(0, 0))
    {
      "Creates the GUI"

      w <<- gwindow(
        "Main window", 
        visible = FALSE,
        parent  = windowPosition
      )

      txt <<- gedit(
        "Initial text in main window.", 
        container = w
      )      

      btn <<- gbutton(
        "Send to sub window", 
        container = w
      )      

      addHandlerChanged(
        btn, 
        handler = function(h, ...) {
          subWindow$setText(getText())
        } 
      )

      visible(w) <- TRUE      
    },
    #other methods to access GUI functionality go here
    getText = function() 
    {
      svalue(txt)
    },
    setText = function(newTxt) 
    {
      svalue(txt) <- newTxt
    }
  )
))  

createMainGui <- function(...)
{
  invisible(mainGui$new(...))
}    
于 2013-03-17T09:41:13.087 に答える
2

リスト内の各ウィンドウのウィジェットを返すだけです。したがって、メイン関数は最後に行list(w = w, txt = txt, btn = btn)を追加して各ウィジェットを返し、関数の終了後にそれらにアクセスできるようにします。

次の例は、機能するコードへの最小の変更ですが、そこに小さな欠陥があり、main相互subwindowからの戻り値への参照が含まれています。コードは機能しますが、もっと複雑なことをしていると、保守が難しくなる可能性があります。

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

main <- function(){
  w <- gwindow(title="Main window",
               visible=FALSE)

  txt <- gtext(text="Initial text in main window.",
               container=w)

  btn <- gbutton("Send to sub window", container=w)

  addHandlerChanged(btn, handler = function(h, ...) {
    svalue(subWindow$txt) <- svalue(mainWindow$txt)
  } )

  visible(w) <- TRUE
  list(w = w, txt = txt, btn = btn)
}

subwindow<- function(text){
  sw <- gwindow(title="Sub window",
                visible=FALSE)

  editedtxt <- gtext(text="",
                     container=sw)

  btn <- gbutton("Send to main window", container=sw)

  addHandlerChanged(btn, handler = function(h, ...) {
    svalue(mainWindow$txt) <- svalue(subWindow$txt)
  } )

  visible(sw) <- TRUE
  list(w = sw, txt = editedtxt, btn = btn)
}

mainWindow <- main()
subWindow <- subwindow()
于 2013-03-17T09:23:10.747 に答える
1

独立した関数を使用し、レシーバーウィジェットのオブジェクト名を事前に知らなくても、gwidget間で情報を渡すことができます。

initMain <- function() {
  w <- gwindow(title="Main window",visible=FALSE)
  txt <- gtext(text="Initial text in main window.",container=w)
  btn <- gbutton("Send to sub window", container=w)

  list(
    run = function(partner) {
      addHandlerChanged(btn, handler = function(h, ...) {
        svalue(partner$txt) <- svalue(txt)
      } )
      visible(w) <- TRUE
    },
    txt = txt
  )
}

initSubWindow<- function() {
  w <- gwindow(title="Sub window",visible=FALSE)
  txt <- gtext(text="huhu",container=w)
  btn <- gbutton("Send to main window", container=w)

  list(
    run = function(partner) {
      addHandlerChanged(btn, handler = function(h, ...) {
        svalue(partner$txt) <- svalue(txt)
      } )
      visible(w) <- TRUE
    },
    txt = txt
  )
}

mw <- initMain()
sw <- initSubWindow()

mw$run(sw)
sw$run(mw)
于 2013-08-22T16:30:04.740 に答える