2014-09-07 5 views
0

На обратной стороне How to add a context menu to a `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) })

, кажется, не получить передается правильное i значение. Это всегда 3. Таким образом, в зависимости от контекстного меню, выполняется только h_ctab_clear(field.nr=3).

Я в тупике, если по той простой причине, что всплывающие подсказки gframe правильны. Но не обработчик, связанный с каждым контекстным меню.

Я подозреваю какой-то объем или аналогичную проблему с h_ctab_clear(field.nr=i), но я не уверен, что не так?

+0

Я понятия не имею, что этот код должен делать, так как это не кажется, [воспроизводимая] (http://stackoverflow.com/questions/5963269/how-to -make-a-great-r-воспроизводимый пример) (т. е. когда я вставляю его в R, я получаю кучу ошибок, начиная с «Нет пакетов инструментальных средств, установленных» из 'gwindow'). Но игнорируя это на данный момент, я предполагаю, что проблема связана с ленивой оценкой значений параметров. Формально что-то вроде force (i) 'поможет превратить значение обещания, если' i' в фактическое значение, но там, где вы бы сказали, что в этом случае неясно. Сделайте код незаменимым. – MrFlick

+0

Код воспроизводимый. Вероятно, вам нужно установить 'install.packages (« gWidgets2RGtk2 »)'. Что касается вашего комментария, я также подозревал что-то, связанное с «ленивой оценкой» или подобным, но я не уверен, как это обойти. – landroni

+0

Конечно, сделают это. Обычно он отлично работает с помощью 'require (gWidgets2)', но, очевидно, он терпит неудачу, когда пользователь не установил 'gWidgets2RGtk2'. Будет более осторожным в следующий раз. – landroni

ответ

1

Я бы предположил, что 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) 
    )) 
) 
+0

Работает очень красиво. Еще раз спасибо. – landroni

+0

Иногда эту проблему можно решить, используя 'sapply' вместо цикла for, так как тогда значение' i' находится внутри среды вызова функции. Другим возможным решением является «силовой» трюк. – jverzani