stephenfin
stephenfin

Reputation: 1467

Pass Python variables to `Tkinter.Tcl().eval()`

I can source a Tcl script, and run a proc from said script like so:

import Tkinter
>>> tclsh = Tkinter.Tcl()
>>> tclsh.eval('source {myscript.tcl}')
>>> tclsh.eval('myproc')
...[output of proc]
>>>

However, should I want to pass variables to this proc, I have to do it like so (assuming the proc takes a dict as a parameter:

>>> tclsh.eval('dict set spec num 10000')
>>> tclsh.eval('dict set spec time 10000')
>>> tclsh.eval('dict set spec rate 10')

Is there an easier, more-Pythonic way to do this from the context of Tkinter? I've seen the variable classes, but they don't seem to have a dict-style variable, or even tie into the Tcl interpreter part of the code at all.

Upvotes: 2

Views: 2996

Answers (1)

schlenk
schlenk

Reputation: 7247

The variable classes are a good idea, but there is no specific dict version of those available, which is a bit ugly, but you can simply use a string version (and take a performance hit due to it, but thats fixable).

So the easy way first. A Tcl dict has a string representation and is convertible from and to its string rep automatically, so if you have a proc that needs a dict, you can simply pass in the string rep for the dict and it just works.

interp = tkinter.Tcl()
myvar = tkinter.StringVar()

def pydict2tcldict(d):
    return tkinter._stringify(list(d.items()))

d = {'num': 10000, 'time': 10000, 'rate': 10}
myvar.set(pydict2tcldict(d))

interp.eval("""source {myscript.tcl}
               myproc $%s""" % myvar._name)

You can of course make things a bit nicer and faster by providing a special dict variable wrapper instead of the slow round trip through the string rep, see the implementation of the variable classes.

But fundamentally tkinter is just missing a few conversion functions in the _tkinter.c module (see AsObj/FromObj/CallArgs) if one added the appropriate code for mappings (trivial), you could simply do this and be done (and it would be reasonably fast):

interp.call("myproc", d)

The patch to modules/_tkinter.c should be pretty trivial, after reading the Tcl dict C API manpage and the Python mapping C-API (https://www.tcl.tk/man/tcl8.6/TclLib/DictObj.htm and https://docs.python.org/2/c-api/mapping.html ).

Upvotes: 5

Related Questions