On the back of How to add a context menu to a `gframe`?, I am trying to create three different gframe
objects with different context-menu handlers. To avoid code duplication, I'm doing this through a loop.
Consider this minimal example:
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
}
The trouble is that for some reason the
handler=function(h, ...){
h_ctab_clear(field.nr=i)
})
does not seem to get passed the correct i
value. It is always 3
. So whichever context-menu is accessed, it's only the h_ctab_clear(field.nr=3)
that gets executed.
I'm stumped if for the simple reason that the gframe
tooltips are all correct. But not the handler associated with each context menu.
I'm suspecting some scope or similar issue with h_ctab_clear(field.nr=i)
, but I'm not sure what is wrong?
I would guess that add3rdmousePopupMenu
is probably taking your handler
function and evaluating it in a different context. At that point, it can't resolve i
because it's a free variable in the function body and the original enclosure environment is no longer available. One possible solution is to explicitly create an enclosure that hold the i
value. To make this easier, we can create a helper function.
makehandler <- function(i) {
force(i);
function(h, ...){
h_ctab_clear(field.nr=i)
}
}
This function will enclose i
and then return a function that you can use as a handler. Then you can use it like
add3rdmousePopupMenu(l_lyt_ctab[[i]],
list(a=gaction(
"Clear field",
icon="clear",
handler=makehandler(i)
))
)