Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Of all the things I dislike about R, one of the biggest is the fact that you can declare a function within the list of arguments to another function. I’ve gotten over it for very minor operations needed by things like lapply, but it can drive me bonkers elsewhere. One such instance is writing an event handler using the gwidgets package. Here’s an example, inspired by the example in “Programming Graphical User Interfaces in R“:

# Create a basic window with an output section
require(gWidgets)
options(guiToolkit = RGtk2)
window = gwindow("File search", visible = FALSE)
paned = gpanedgroup(cont = window)
frmOutput = gframe("Output: ", cont=paned, horizontal = FALSE)
txtOutput = gtext("", cont = frmOutput, expand = TRUE)
size(txtOutput) = c(350, 200)

# Create a button to open a .csv file
btnImportFile = gfilebrowse(text = "Select a file ", quote = FALSE, type = "open", cont = container, filter = "*.csv")
svalue(txtOutput) = svalue(h\$obj)
})


OK, that was a fairly tame handler. All that we’re doing is placing the name of the file into the output area. What I’d like to do is use the output to show the names of columns contained in the file. Here’s what that would look like:

btnDescribeColumns = gbutton(text = "Describe columns", cont = container)
filename = svalue(txtOutput)
if( filename == ""){
} else {
svalue(txtOutput) = names(df)
}
})


That’s not too dreadful in isolation, but the event handler sits in the same function where I’ve defined another event handler. I’m now defining two functions inside a third function. For any rich interface, this will quickly get complex. Making changes to a specific handler means trolling through one giant, monolithic function. (Yes, yes, I could just search, but the aesthetics of my code are still poor.)

AddBtnDescribeColumns = function(container, txtOutput){
require(gWidgets)
btnDescribeColumns = gbutton(text = "Describe columns", cont = container)

filename = svalue(txtOutput)
if( filename == ""){
} else {
svalue(txtOutput) = names(df)
}
})

return (btnDescribeColumns)
}


With a similar approach to the file open button (not shown, but available on Github), the main function for my dialog box is beginning to look fairly readable. Note that I must declare the output box before the buttons, so that it may be passed to the button constructors.

Main = function(WhichToolkit = "RGtk2"){
require(gWidgets)
options(guiToolkit = WhichToolkit)

window = gwindow("File search", visible = FALSE)

paned = gpanedgroup(cont = window)

group = ggroup(cont = paned, horizontal = FALSE)
frmOutput = gframe("Output: ", cont=paned, horizontal = FALSE)

txtOutput = gtext("", cont = frmOutput, expand = TRUE)

size(txtOutput) = c(350, 200)

visible(window) = TRUE
}


Another nice aspect of this construct is that I can declare multiple copies of the same button and place them wherever I like. They’ll all have the same event handler, which I only need to code once.

I’ve been working with gWidgets for a sum total of about three hours, so there may be something obvious I’ve missed. If so, please feel free to comment.