0
votes

I'm creating a user interface using tcl/tk in R. I need to include several buttons and other widgets in a single top level window and I need to group some widgets into a container within the top level window. I've been using tkframe() as the container, which as far as I know requires tkpack() for widget placement. But I'm using tkgrid() for placing the frame and other widgets in the top level window. I suspect this is causing the inconsistencies I'm experiencing when I try to run the interface function. Can tkpack() and tkgrid() be used together? If not, is there another type of container that I can use instead of tkframe() that will work better with tkgrid()?

Here is some simplified code as an example that works with only tkpack():

 require(tcltk)   
 tclRequire("BWidget")



interface1 <- function(){

  ww <- tktoplevel()

  buttons.f <- tkframe(ww)

   getdata.b <- tkbutton(buttons.f, text = "Import Data", command = function() {
    filepath <<- file.choose()
    })
   viewdata.b <- tkbutton(buttons.f, text = "Print Data", command = function() {
    print(read.csv(filepath))
    })
   tkpack(getdata.b, fill = "both")
   tkpack(viewdata.b, fill = "both")

  tree.f = tkframe(ww)

   treeWidget = tkwidget(tree.f,"Tree", width = 30, height = 6)

   tkinsert(treeWidget,"end","root","Species1",text="Elk")
   tkinsert(treeWidget,"end","root","Species2",text="Deer")

   tkpack(treeWidget,fill='both',expand=1)

   getvars  <- function() { 
    selection <<- tclvalue(tcl(treeWidget,"selection","get")) 
    print(selection)
    }

  run.b <- tkbutton(ww, text = "Run", command = getvars)

  close.b <- tkbutton(ww, text = "Close", command = function(){
    tkdestroy(ww)
    filepath <<- NULL
    })

  tkpack(buttons.f)
  tkpack(tklabel(ww,text="Select One:"))
  tkpack(tree.f)
  tkpack(run.b, fill = "both")
  tkpack(close.b, fill = "both")
}
interface1()

But with tkgrid() it doesn't always display correctly:

interface2 <- function(){

  ww <- tktoplevel()

  buttons.f <- tkframe(ww)

   getdata.b <- tkbutton(buttons.f, text = "Import Data", command = function() {
    filepath <<- file.choose()
    })
   viewdata.b <- tkbutton(buttons.f, text = "Print Data", command = function() {
    print(read.csv(filepath))
    })
   tkpack(getdata.b, fill = "both")
   tkpack(viewdata.b, fill = "both")

  tree.f = tkframe(ww)

   treeWidget = tkwidget(tree.f,"Tree", width = 30, height = 6)

   tkinsert(treeWidget,"end","root","Species1",text="Elk")
   tkinsert(treeWidget,"end","root","Species2",text="Deer")

   tkpack(treeWidget,fill='both',expand=1)

   getvars  <- function() { 
    selection <<- tclvalue(tcl(treeWidget,"selection","get")) 
    print(selection)
    }

  run.b <- tkbutton(ww, text = "Run", command = getvars)

  close.b <- tkbutton(ww, text = "Close", command = function(){
    tkdestroy(ww)
    filepath <<- NULL
    })

  tkgrid(buttons.f, pady = 10, columnspan = 2)
  tkgrid(tklabel(ww,text="Select One:"), columnspan = 2)
  tkgrid(tree.f, columnspan = 2)
  tkgrid(run.b, close.b, padx = 20, pady = 10)
}
interface2()

Since I would prefer to use tkgrid, can anyone identify whether the combination of tkgrid/tkpack is causing the error or can anyone suggest an alternative to tkframe? Thanks for the help!

(I'm sure there's a great package to run this task, but I'm creating an interface for a project at work and I've been directed not to use any packages that don't come with base R)

1
You can't use grid and pack together in the same frame. You can create additional frames, and grid or pack (but not both) can be used to put the widgets into the additional frames. In Tcl, there is no requirement that pack be used.Brad Lanam

1 Answers

1
votes

Strictly, you can use both the packer and the gridder in the same frame if you turn off geometry propagation for (at least) one of them. If you don't, they fight over what the size of the parent frame should be. But you probably don't want to do that in the first place; it's very unlikely that that's a widget layout that you would need, as the widgets would be stacked on top of each other and not kept from overlapping.

Using the packer in a frame and the gridder in a sub-frame of that, or the other way round, is entirely reasonable. It's almost certainly what you want to do.