如何在 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()
编辑1:
我在下面做了一个稍微更小的例子,它适用于你描述的两个工具包。目的是确保内部功能按预期工作,他们确实做到了。
为了进一步追踪问题,我编辑了上面的第一个代码示例以包含手动触发内部功能的按钮。按钮工作,可以读取状态并由 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()
编辑2:
感谢@jverzani 的提示,我已经按照您的建议尝试了 addHandlerUnrealize。这解决了不读取 tcltk 的任何值的问题。然而,我花了一些时间来解决问题并让它与两个工具包一起工作——window 无法关闭。我没有在文档中找到太多内容,但通过反复试验,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 所做的那样,但不能保证此时可以访问小部件。正如@jverzani 在评论中指出的那样,解决方案是改用 addHandlerUnrealize
:
You should try addHandlerUnrealize here (though I don't know if this
works for RGtk2 and can't test). That will call destroy as long as
your handler does not return FALSE but will execute before the destroy
event so your widgets will still be available to read from. – jverzani
Jan 24 at 16:38
有趣的是,示例代码揭示了发出 window 销毁信号的不同实现(请参阅原始 post 了解解决方法)。请注意,@jverzani 考虑推出一个修复程序,这将改变这一点。
基本问题似乎是我无法从内部函数检索小部件的状态。
我正在尝试使用与 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()
编辑1: 我在下面做了一个稍微更小的例子,它适用于你描述的两个工具包。目的是确保内部功能按预期工作,他们确实做到了。
为了进一步追踪问题,我编辑了上面的第一个代码示例以包含手动触发内部功能的按钮。按钮工作,可以读取状态并由 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()
编辑2:
感谢@jverzani 的提示,我已经按照您的建议尝试了 addHandlerUnrealize。这解决了不读取 tcltk 的任何值的问题。然而,我花了一些时间来解决问题并让它与两个工具包一起工作——window 无法关闭。我没有在文档中找到太多内容,但通过反复试验,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 所做的那样,但不能保证此时可以访问小部件。正如@jverzani 在评论中指出的那样,解决方案是改用 addHandlerUnrealize
:
You should try addHandlerUnrealize here (though I don't know if this works for RGtk2 and can't test). That will call destroy as long as your handler does not return FALSE but will execute before the destroy event so your widgets will still be available to read from. – jverzani Jan 24 at 16:38
有趣的是,示例代码揭示了发出 window 销毁信号的不同实现(请参阅原始 post 了解解决方法)。请注意,@jverzani 考虑推出一个修复程序,这将改变这一点。