r-通过循环分配处理程序的问题



在"如何将上下文菜单添加到`gframe`?"的背面?,我试图用不同的上下文菜单处理程序创建三个不同的gframe对象。为了避免代码重复,我通过一个循环来执行此操作。

考虑这个最小的例子:

require(gWidgets2)
require(gWidgets2RGtk2)
w <- gwindow()
gg <- gvbox(cont=w)                   
f_lyt_ctab <- list()
l_lyt_ctab <- list()
h_ctab_clear  <- function(field.nr=NULL){
    stopifnot(!is.null(field.nr))
    print(field.nr)
}
lyt_ctab <- glayout(homogeneous=F, cont=gg, expand=TRUE, fill=T)
field.nms <- c("Row Fields", "Column Fields", "Values")
for(i in 1:3){
    lyt_ctab[1,i, expand=TRUE, fill=T] <- 
        f_lyt_ctab[[i]] <- gframe("", horizontal=FALSE,
                                  container=lyt_ctab, expand=TRUE, fill=T)
    ##have gframe with custom label (and context menu)
    l_lyt_ctab[[i]] <- glabel(field.nms[i])
    tooltip(l_lyt_ctab[[i]]) <- paste(
        "Right-click on", field.nms[i], "to clear field variables")
    print(i)
    print(field.nms[i])
    add3rdmousePopupMenu(l_lyt_ctab[[i]], 
                         list(a=gaction("Clear field", icon="clear", 
                                        handler=function(h, ...){
                                            h_ctab_clear(field.nr=i)
                                        })))
    f_lyt_ctab[[i]]$block$setLabelWidget(l_lyt_ctab[[i]]$block)         # the voodoo
    l_lyt_ctab[[i]]$widget$setSelectable(FALSE)           # may not be needed
}

问题是由于某种原因

handler=function(h, ...){ h_ctab_clear(field.nr=i) })

似乎没有通过正确的CCD_ 3值。它总是3。因此,无论访问哪个上下文菜单,都只能执行h_ctab_clear(field.nr=3)

如果gframe工具提示都是正确的,我很困惑。但不是与每个上下文菜单关联的处理程序。

我怀疑h_ctab_clear(field.nr=i)有一些范围或类似的问题,但我不确定出了什么问题?

我猜add3rdmousePopupMenu可能正在使用handler函数,并在不同的上下文中对其求值。此时,它无法解析i,因为它是函数体中的一个自由变量,并且原始外壳环境不再可用。一种可能的解决方案是显式创建一个包含i值的存储模块。为了更简单,我们可以创建一个助手函数。

makehandler <- function(i) {
    force(i); 
    function(h, ...){
        h_ctab_clear(field.nr=i)
    }
}

此函数将包含i,然后返回一个可以用作处理程序的函数。然后你可以像一样使用它

add3rdmousePopupMenu(l_lyt_ctab[[i]], 
    list(a=gaction(
        "Clear field", 
        icon="clear", 
        handler=makehandler(i)
    ))
)

最新更新