List boxes in R TclTk

The following examples illustrate how to use a list box in a Tk window. The first example does not have a scrollbar, so it is simpler.

List box with tk2listbox()

library(tcltk2)

win1 <- tktoplevel()
win1$env$lst <- tk2listbox(win1, height = 4, selectmode = "single")
tkgrid(tk2label(win1, text = "What's your favorite fruit?", justify = "left"),
tkgrid(win1$env$lst, padx = 10, pady = c(5, 10))
fruits <- c("Apple", "Orange", "Banana", "Pear", "Apricot")
for (fruit in fruits)
tkinsert(win1$env$lst, "end", fruit)
# Default fruit is Banana.  Indexing starts at zero.
tkselection.set(win1$env$lst, 2)

onOK <- function() {
fruitChoice <- fruits[as.numeric(tkcurselection(win1$env$lst)) + 1]
tkdestroy(win1)
msg <- paste0("Good choice! ", fruitChoice, "s are delicious!")
tkmessageBox(message = msg)
}
win1$env$butOK <-tk2button(win1, text = "OK", width = -6, command = onOK)
tkgrid(win1$env$butOK, padx = 10, pady = c(5, 15))

The code above produces the following window:

The user can then select their favorite fruit with the mouse:

The tk2listbox() function automatically adds a scrollbar. With the tcltk version (tklistbox()), you have to add it manually yourself and it requires much more code for the same result. The tk2listbox() function also eases the initial filling of the list and the preselection of items, as it will be done in the second example here under.

Prefilling of a list and deletion of items from a list

Here is a multiple selection list that is prefilled:

win2 <- tktoplevel()
tkgrid(tk2label(win2, text = "Please delete the fruit(s) which you don't like.",
wraplength = 200, justify = "left"),
padx = 10, pady = c(15, 5), sticky = "w", columnspan = 2)
# Note that 'selection' uses indices starting at 1, like R and not Tcl/Tk!
win2$env$lst <- tk2listbox(win2,
values <- c("Apple", "Orange", "Banana", "Pear"),
selection = 3, height = 4, selectmode = "extended")
tkgrid(win2$env$lst, padx = 10, pady = c(5, 10), sticky = "ew", columnspan = 2)

onDelete <- function() {
fruitsSel <- as.integer(tkcurselection(win2$env$lst))
# Warning! We have to delete elements from bottom to top, otherwise
# as soon as we delete an element in the front of the list, the indices
# of the remaining items are shifted!
for (i in rev(fruitsSel))
tkdelete(win2$env$lst, i)
}
win2$env$butDel <- tk2button(win2, text = "Delete", width = -6,
command = onDelete)

onOK <- function() {
fruitsRemaining <- as.character(tkget(win2$env$lst, 0, "end"))
tkdestroy(win2)
if (!length(fruitsRemaining)) {
msg <- "Oh no! You don't like fruits at all, isn't it?"
} else {
msg <- paste0("So, you do like these fruits: ",
paste(fruitsRemaining, collapse = ", "))
}
tkmessageBox(message = msg)
}
win2$env$butOK <-tk2button(win2, text = "OK ", width = -6, command = onOK)

tkgrid(win2$env$butDel, win2$env$butOK, padx = 10, pady = c(10, 15))

Running the code above gives the following window:

Select “Orange” from the list, then press <Ctrl> key and select “Pear”. You got a multiple selection:

Click Delete to remove these fruits from the list.

Click OK to get this message: