如何在使用tkinter时将tcl的stdout获取到Python字符串变量中?

2 投票
1 回答
1914 浏览
提问于 2025-04-15 16:08

我有以下的python代码...

import Tkinter

root = Tkinter.Tk()

root.tk.eval('puts {printed by tcl}')

这段代码会在屏幕上打印“printed by tcl”。我想知道怎么才能把tcl解释器打印到屏幕上的内容捕捉到一个python字符串里。

这是我正在做的一个简化示例。我有一个用python写的自动化系统,但有一台新设备是通过tcl的接口来控制的。每个tcl命令都会打印一些信息,比如“已连接”或者“连接失败”。我需要把这些信息捕捉到python字符串里,这样自动化系统才能知道发生了什么。例如,如果设备没有连接,自动化系统就可以重新尝试连接命令。

谢谢

来自Nick

1 个回答

5

如果你运行的代码是直接在屏幕上打印内容,并且你是通过 root.tk.eval() 来调用它的,那么你是无法捕捉到这些输出的。不过,你可以在 tcl 代码中重新定义 "puts" 这个命令,让它做你想要的事情。这就是 Tcl 的一个优点——没有保留字。

你只需要在 tcl 解释器中创建一个叫 "puts" 的过程,但要确保它的功能和原来的 "puts" 一模一样(比如要支持 "-nonewline" 参数,能够写入文件等等)。当 puts 通常在屏幕上打印内容时,你可以让它做其他事情,比如写入一个套接字,或者仅仅返回它应该打印的字符串。

大致上(未经测试,且不考虑 -nonewline 的情况):

root.tk.eval('''
rename puts original_puts 
proc puts {args} {
    if {[llength $args] == 1} {
        return "=> [lindex $args 0]"
    } else {
        eval original_puts $args
    }
}
''')

foo = root.tk.eval('puts "hello, world"')
print foo
=> hello, world

你需要稍微用点心,确保不会破坏那些期望标准 "puts" 语句的 tcl 代码,但这并不难。只要确保处理好一个参数的情况、"-nonewline" 的第一个参数,以及两个参数的情况(文件描述符和字符串)。

如果你调用 eval 并且它执行了两个 puts 语句,或者先执行一个 puts 然后执行其他代码,可能会有点复杂,因为 eval 的结果是最后一个语句的结果。不过,你可以通过让 puts 将输出缓存在一个全局变量中,然后每次执行 eval 时返回这个变量的结果来解决这个问题。

所以,稍微跳出框框思考一下,你就能找到解决方案。Tcl 是非常灵活的。

撰写回答