将Python变量传递给`Tkinter.Tcl().eval()`

2 投票
1 回答
2854 浏览
提问于 2025-04-18 17:09

我可以加载一个Tcl脚本,并像这样运行其中的一个proc

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

但是,如果我想给这个proc传递一些变量,我必须这样做(假设这个proc需要一个dict作为参数):

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

有没有更简单、更符合Python风格的方法来在Tkinter中做到这一点?我见过变量类,但它们似乎没有字典风格的变量,甚至没有和Tcl解释器的部分连接起来。

1 个回答

5

变量类的想法很好,但目前没有专门的字典版本,这有点不太方便。不过,你可以简单地使用字符串版本(这样会影响性能,但这个问题是可以解决的)。

先说简单的方法。Tcl 的字典有一个字符串表示形式,并且可以自动从字符串转换为字典,反之亦然。所以如果你有一个需要字典的过程,你可以直接传入字典的字符串表示,它就能正常工作。

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)

当然,你可以通过提供一个特殊的字典变量包装器来让事情变得更好更快,而不是通过字符串表示进行慢速转换,具体可以参考变量类的实现。

但从根本上说,tkinter 只是缺少了一些在 _tkinter.c 模块中的转换函数(可以看看 AsObj/FromObj/CallArgs),如果添加适当的映射代码(这很简单),你就可以直接这样做,事情就解决了(而且速度也会相当快):

interp.call("myproc", d)

modules/_tkinter.c 的修改应该是相当简单的,阅读 Tcl 字典 C API 的手册和 Python 映射 C-API 后,你会发现这很容易实现(可以参考 https://www.tcl.tk/man/tcl8.6/TclLib/DictObj.htmhttps://docs.python.org/2/c-api/mapping.html)。

撰写回答