What is the idiomatic way of calling Tcl functions that expect a Tcl script as an argument?


#1

For example the bind command:

grid [ttk::label .l -text "Starting..."] 
bind .l <Enter> {.l configure -text "Moved mouse inside"}
bind .l <Leave> {.l configure -text "Moved mouse outside"}
bind .l <1> {.l configure -text "Clicked left mouse button"}
bind .l <Double-1> {.l configure -text "Double clicked"}
bind .l <B3-Motion> {.l configure -text "right button drag to %x %y"}

I know I can do something like this:

grid(ttk::label(".l", text: "Starting...")); 
bind(".l","<Enter>", {".l", "configure", "-text", "Moved mouse inside"});
bind(".l","<Leave>", {".l", "configure", "-text", "Moved mouse outside"});
bind(".l","<1>", {".l", "configure", "-text", "Clicked left mouse button"});
bind(".l","<Double-1>", {".l", "configure", "-text", "Double clicked"});
bind(".l","<B3-Motion>", {".l", "configure", "-text", "right button drag to %x %y"});

or

grid(ttk::label(".l", text: "Starting..."));
bind(".l", "<Enter>", ".l configure -text \"Moved mouse inside\"");
bind(".l", "<Leave>", ".l configure -text \"Moved mouse outside\"");
bind(".l", "<1>", ".l configure -text \"Clicked left mouse button\"");
bind(".l", "<Double-1>", ".l configure -text \"Double clicked\"");
bind(".l", "<B3-Motion>", ".l configure -text \"right button drag to %x %y\"");

Is there a less ugly way?

I think you can’t pass a L function by reference because the bind command expect a Tcl script, right?


#2

So the good news is that a Little function is a Tcl proc, so if your args are simple strings it just works.

The bad news is we haven’t done the work to make Tk super pleasant yet. In particular, passing fields of a struct or a hash isn’t possible because those are Tcl list / dict elements and there is no way to pass a reference of an object, only of a variable. Damon and I have been discussing the idea of making a Struct type that is implemented with a Tcl array because those you can pass.

So I think you are stuck with ugly but Damon is the expert (and he’s sort of spotty this week, not at his computer).


#3

Generally, I try to never include an actual script in a bind event, though I do sometimes when I’m just slapping stuff together. So, in most cases, you want to bind an event to a function like this:

bind(".l", "<Enter>", &some_callback_function);

If you wanted to pass args, I would do:

bind(".l", "<Enter>", {&some_callback_function, "%x", "%y"});

Ugly, yes, but as Larry said, we’re working on ideas to make L and Tk bind more tightly and remove some of this ugliness. :slight_smile:


#4

Ok thanks.
It looks a little bit better:

void change_text (string text) {
    .l("configure", text: text);
}
grid(ttk::label(".l", text: "Starting..."));
bind(".l", "<Enter>", {&change_text, "Moved mouse inside"});
bind(".l", "<Leave>", {&change_text, "Moved mouse outside"});
bind(".l", "<1>", {&change_text, "Clicked left mouse button"});
bind(".l", "<Double-1>", {&change_text, "Double clicked"});
bind(".l", "<B3-Motion>", {&change_text, "right button drag to %x %y"});

I am translating the code from the TkDocs tutorial to L.
I have wrote this script that automates the translation of most of the Tk commands in de tutorial.


#5

Love that script, nicely written. We should include in the examples.