簡體   English   中英

如何在gWidgets2tcltk中檢索復選框狀態(在gWidgets2RGtk2中有效)

[英]How to retrieve checkbox state in gWidgets2tcltk (works in gWidgets2RGtk2)

基本問題似乎是我無法從內部函數中檢索小部件的狀態。

我正在嘗試使用與gWidgets2tcltk兼容的gWidgets2RGtk2開發我的程序包。 該軟件包包括一個圖形用戶界面,實現了保存gui狀態的可能性。 該代碼按使用RGtk2的預期工作,但是使用tcltk存在問題。 我嘗試了if構造的各種變體。 我感到奇怪的是,我可以從.loadState內部讀取狀態,而不能從.saveState內部讀取狀態。 他們是從不同的地方打電話來的,那么問題可能與環境有關嗎? 我被困了一段時間,所以也許我對一個顯而易見的解決方案視而不見,或者也許有一種更好的方法來完成我要執行的行為。 下面的代碼說明了該問題。

我在Windows 10系統,gWidgets2tcltk_1.0-6和gWidgets2_1.0-7上使用R版本3.5.1。

# The code works as intended using RGtk2.
require(gWidgets2RGtk2)
options("guiToolkit"="RGtk2")

# The code does not work when using tcltk.
# require(gWidgets2tcltk)
# options("guiToolkit" = "tcltk")

saveStateExample <- function(env = parent.frame(), savegui = NULL) {

  # savegui = NULL, Default when started manually as GUI wrapped function.
  # savegui = TRUE, Passed from main GUI when started as part of full program.
  # savegui = FALSE, Passed from main GUI when started as part of full program.


  # Create windows.
  w <- gwindow(title = "Checkbox behaviour", visible = FALSE)

  # Runs when window is closed.
  addHandlerDestroy(w, handler = function(h, ...) {

    # Save GUI state.
    .saveState()
  })

  # Create container.
  g <- ggroup(container = w, expand = TRUE, horizontal = FALSE)

  # Add checkbox to control saving gui statesa.
  save_state_chk <- gcheckbox(text = "Save state", checked = FALSE, container = g)

  # Add a text widget.
  text_edt <- gedit(container = g)

  # Add buttons to manually trigger the functions.
  load_btn <- gbutton(text = "Run .loadState", container = g)
  save_btn <- gbutton(text = "Run .saveState", container = g)

  addHandlerChanged(load_btn, handler = function(h, ...) {

    .loadState()

  })

  addHandlerChanged(save_btn, handler = function(h, ...) {

    .saveState()

  })

  # Internal function ---------------------------------------------------------

  .loadState <- function() {
    message(".loadState")
    message("save_state_chk was ", svalue(save_state_chk))
    message("savegui was ", savegui)

    # First check if save argument was passed.
    if (!is.null(savegui)) {
      # Update widget with passed value.
      svalue(save_state_chk) <- savegui
      message("save_state_chk set to ", savegui)
      message("save_state_chk is ", svalue(save_state_chk))
    } else {
      # Look for previously saved flag.
      if (exists(".package_savegui", envir = env, inherits = FALSE)) {
        svalue(save_state_chk) <- get(".package_savegui", envir = env)
        message(".package_savegui loaded")
      }
    }

    message("LOAD SAVED STATE")

    # Then load settings if true.
    if (svalue(save_state_chk)) {
      if (exists(".package_text", envir = env, inherits = FALSE)) {
        svalue(text_edt) <- get(".package_text", envir = env)
      }

      message("GUI saved state loaded")
    } else {
      message("GUI default state loaded")
    }
  }

  # Internal function ---------------------------------------------------------

  .saveState <- function() {
    message(".saveState")
    message("save_state_chk was ", svalue(save_state_chk))
    message("savegui was ", savegui)

    # First check status of save flag.
    if (is.null(svalue(save_state_chk))) {
      message("save_state_chk=NULL")
    } else {
      message("SAVE STATE")
      # Then save settings if true.
      if (svalue(save_state_chk)) {
        assign(x = ".package_savegui", value = svalue(save_state_chk), envir = env)
        assign(x = ".package_text", value = svalue(text_edt), envir = env)

        message("GUI state saved")
      } else { # or remove all saved values if false.

        if (exists(".package_savegui", envir = env, inherits = FALSE)) {
          remove(".package_savegui", envir = env)
        }
        if (exists(".package_text", envir = env, inherits = FALSE)) {
          remove(".package_text", envir = env)
        }

        message("GUI state cleared")
      }
    }
  }

  # Run internal function to load state before showing window.
  .loadState()
  visible(w) <- TRUE
}

# Open gui.
saveStateExample()

EDIT1:我在下面做了一個最小化的示例,該示例可用於您所描述的兩個工具箱。 目的是確保內部功能按預期工作,並且做到了。

為了進一步找出問題,我編輯了上面的第一個代碼示例,其中包括手動觸發內部功能的按鈕。 按鈕起作用,狀態可以讀取,並通過message功能進行打印。 但是,當銷毀處理程序被觸發時(使用tcltk工具包),該狀態仍未讀取。 似乎使用tcltk工具包破壞了內容為時過早,但沒有使用RGtk2工具包破壞了內容。 有任何想法嗎?

# The code works as intended using RGtk2 and tcltk.
# require(gWidgets2RGtk2)
# options("guiToolkit"="RGtk2")

 require(gWidgets2tcltk)
 options("guiToolkit" = "tcltk")

saveStateExample <- function() {

  # Create windows.
  w <- gwindow(title = "Checkbox behaviour", visible = FALSE)

  # Runs when window is closed.
  addHandlerDestroy(w, handler = function(h, ...) {

    message("Window destroyed")
    message("save_state_chk is ", svalue(save_state_chk))
    message("text_edt is ", svalue(text_edt))

  })

  # Create container.
  g <- ggroup(container = w, expand = TRUE, horizontal = FALSE)

  # Add checkbox to control saving gui statesa.
  save_state_chk <- gcheckbox(text = "Save state", checked = FALSE, container = g)

  # Add a text widget.
  text_edt <- gedit(container = g)

  # Add buttons.
  check_btn <- gbutton(text = "Check", container = g)
  uncheck_btn <- gbutton(text = "UnCheck", container = g)

  addHandlerChanged(check_btn, handler = function(h, ...) {

    .setCheckTrue()

  })

  addHandlerChanged(uncheck_btn, handler = function(h, ...) {

    .setCheckFalse()

  })

  # Internal function ---------------------------------------------------------

  .setCheckTrue <- function() {

    message(".setCheckTrue")
    message("save_state_chk was ", svalue(save_state_chk))

    svalue(save_state_chk) <- TRUE
    message("save_state_chk is ", svalue(save_state_chk))
    message("text_edt is ", svalue(text_edt))

  }

  # Internal function ---------------------------------------------------------

  .setCheckFalse <- function() {

    message(".setCheckFalse")
    message("save_state_chk was ", svalue(save_state_chk))

    svalue(save_state_chk) <- FALSE
    message("save_state_chk is ", svalue(save_state_chk))
    message("text_edt is ", svalue(text_edt))

  }

  # Show window.
  visible(w) <- TRUE

}

# Open gui.
saveStateExample()

EDIT2:感謝提示@jverzani,我已經按照您的建議嘗試了addHandlerUnrealize。 這就解決了不讀取tcltk的任何值的問題。 但是,我花了一些時間來整理內容並使其與兩個工具箱一起使用-無法關閉窗口。 我在文檔中沒有找到太多內容,但是通過反復試驗,似乎RGtk2和tcltk實施了不同的物流。 要繼續進行銷毀事件,RGtk2需要為FALSE ,而tcltk需要為TRUE 下面是第一個代碼示例的固定版本:

# The code now works as intended using both RGtk2 and tcltk!
# require(gWidgets2RGtk2)
# options("guiToolkit"="RGtk2")
require(gWidgets2tcltk)
options("guiToolkit" = "tcltk")

saveStateExample <- function(env = parent.frame(), savegui = NULL) {

  # savegui = NULL, Default when started manually as GUI wrapped function.
  # savegui = TRUE, Passed from main GUI when started as part of full program.
  # savegui = FALSE, Passed from main GUI when started as part of full program.


  # Create windows.
  w <- gwindow(title = "Checkbox behaviour", visible = FALSE)

  # Runs when window is closed.
  addHandlerUnrealize(w, handler = function(h, ...) {

    # Save GUI state.
    .saveState()

    message("UNREALIZE!")

    # Check which toolkit we are using.
    if (gtoolkit() == "tcltk") {
      message("tcltk, returned TRUE!")
      return(TRUE) # Destroys window under tcltk, but not RGtk2.
    } else {
      message("RGtk2, returned FALSE!")
      return(FALSE) # Destroys window under RGtk2, but not with tcltk.
    }
  })

  # Runs when window is closed.
  addHandlerDestroy(w, handler = function(h, ...) {
    message("DESTROY!")
    # addHandlerDestroy does not care of return type for either RGtk2 or tcltk?
  })

  # Create container.
  g <- ggroup(container = w, expand = TRUE, horizontal = FALSE)

  # Add checkbox to control saving gui statesa.
  save_state_chk <- gcheckbox(text = "Save state", checked = FALSE, container = g)

  # Add a text widget.
  text_edt <- gedit(container = g)

  # Add buttons to manually trigger the functions.
  load_btn <- gbutton(text = "Run .loadState", container = g)
  save_btn <- gbutton(text = "Run .saveState", container = g)

  addHandlerChanged(load_btn, handler = function(h, ...) {
    .loadState()
  })

  addHandlerChanged(save_btn, handler = function(h, ...) {
    .saveState()
  })

  # Internal function ---------------------------------------------------------

  .loadState <- function() {
    message(".loadState")
    message("save_state_chk was ", svalue(save_state_chk))
    message("savegui was ", savegui)

    # First check if save argument was passed.
    if (!is.null(savegui)) {
      # Update widget with passed value.
      svalue(save_state_chk) <- savegui
      message("save_state_chk set to ", savegui)
      message("save_state_chk is ", svalue(save_state_chk))
    } else {
      # Look for previously saved flag.
      if (exists(".package_savegui", envir = env, inherits = FALSE)) {
        svalue(save_state_chk) <- get(".package_savegui", envir = env)
        message(".package_savegui loaded")
      }
    }

    message("LOAD SAVED STATE")

    # Then load settings if true.
    if (svalue(save_state_chk)) {
      if (exists(".package_text", envir = env, inherits = FALSE)) {
        svalue(text_edt) <- get(".package_text", envir = env)
      }

      message("GUI saved state loaded")
    } else {
      message("GUI default state loaded")
    }
  }

  # Internal function ---------------------------------------------------------

  .saveState <- function() {
    message(".saveState")
    message("save_state_chk was ", svalue(save_state_chk))
    message("savegui was ", savegui)

    # First check status of save flag.
    if (is.null(svalue(save_state_chk))) {
      message("save_state_chk=NULL")
    } else {
      message("SAVE STATE")
      # Then save settings if true.
      if (svalue(save_state_chk)) {
        assign(x = ".package_savegui", value = svalue(save_state_chk), envir = env)
        assign(x = ".package_text", value = svalue(text_edt), envir = env)

        message("GUI state saved")
      } else { # or remove all saved values if false.

        if (exists(".package_savegui", envir = env, inherits = FALSE)) {
          remove(".package_savegui", envir = env)
        }
        if (exists(".package_text", envir = env, inherits = FALSE)) {
          remove(".package_text", envir = env)
        }

        message("GUI state cleared")
      }
    }
  }

  # Run internal function to load state before showing window.
  .loadState()
  visible(w) <- TRUE
}

# Open gui.
saveStateExample()

問題的原因是addHandlerDestroy不適合保存小部件狀態。 它可能像RGtk2一樣起作用,但是不能保證此時可以訪問小部件。 該解決方案是使用addHandlerUnrealize代替,如通過在評論@jverzani指出:

您應該在這里嘗試addHandlerUnrealize(盡管我不知道這是否適用於RGtk2並且無法測試)。 只要您的處理程序不返回FALSE,但將在destroy事件之前執行,則將調用destroy,因此仍可從中讀取小部件。 – jverzani 1月24日16:38

有趣的是,示例代碼顯示了發信號通知窗口破壞的不同實現(有關變通方法,請參閱原始文章)。 注意,@ jverzani考慮推送修復程序,這將改變此情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM