如何在Tkinter应用程序中嵌入终端?

33

我希望在我的Tkinter主窗口中嵌入一个终端。我想要一个子窗口,其中运行一个Bash终端。我还想能够让我的程序与终端交互,至少我想读取当前工作目录并/或者设置它。

我不知道是否真的不可能。过去我使用Perl/Tk做到了这一点,因此也许可以在这里复制它。

我当时使用的代码类似于:

$frame3=$mw->Frame(-borderwidth=>2, -relief=>'groove', # -label=>'stuff for thought',
                             -labelBackground=>CADRAWWINCOLOR,-background=>CADRAWWINCOLOR);                 

$cv=$frame3->Canvas(-height=>$cvheight,-width=>$cvwidth,-background=>CADRAWWINCOLOR,
                             -bg => CADRAWWINCOLOR,
                             -relief => 'sunken')->pack(-expand => 1, -fill => 'both');

# this Frame is needed for including the xterm in Tk::Canvas 
my $xtermContainer = $cv->Frame(-container => 1);
my $xtid = $xtermContainer->id();
# converting the id from HEX to decimal as xterm requires a decimal Id
my ($xtId) = sprintf hex $xtid;

my $dcontitem = $cv->createWindow($xtermWidth/2,$xtermHeight/2,
                                       -window => $xtermContainer,
                                       -width => $xtermWidth,
                                       -height => $xtermHeight,
                                       -state => 'normal');

system("xterm -into $xtId -fn $fontname -geometry $geometry +sb -bg black -fg white -e ./xtermjob.pl $AAfname 5 &"); 

这里的$mw是主要的Tk窗口。

当然,我完全同意Bryan的观点:虽然我以前从未使用过GUI库进行编程,但我的程序(相当大,有点像维基百科)运行非常良好,且用于GUI本身的代码量惊人地少。

我尝试翻译这段Perl代码,但我遇到了ID问题。

我发现从Tkinter中提取ID的方法唯一的参考资料是在Effbot,但当我使用它时,我得到了'AttributeError: Frame instance has no attribute 'window_id',所以肯定出了点问题:

termf = Frame(root)
termf.pack(side=BOTTOM, fill=X)
id=termf.window_id()  
os.system("xterm -into %d -fn -misc-fixed-medium-r-normal--8-80-75-75-c-50-iso10646-1 -geometry 150x150+0+0 +sb -bg black -fg white -e /root/.bashrc &" % id);  

1
你可以在PyGTK应用程序中嵌入VTE,但我不知道在Tkinter中是否有类似的东西。你使用Tkinter有什么特别的原因吗? - Keith
1
只是因为我发现它比其他小部件更容易学习! - alessandro
2
@Keith:为什么你说pygtk有更好的未来?Tkinter已经存在很长时间了,而且是Python核心的一部分。我认为它不会在很长一段时间内被从Python中移除。 - Bryan Oakley
4
@Keith:我认为你对“只能达到这一程度”这个评论是错误的。我使用Tk(承认是使用tcl/tk而不是python/tkinter)创建了一些非常复杂且成功的商业应用程序。事实上,许多应用程序不需要Tkinter没有提供的任何东西,特别是考虑到在最近版本的Tkinter中添加了ttk小部件。 - Bryan Oakley
1
@Keith:您似乎暗示使用pygtk可以实现这一点。这个问题(http://stackoverflow.com/questions/5993390/embed-interactive-shell-vte-in-a-pygtk-gui-to-manipulate-its-own-widgets)询问如何在pygtk中实现它 - 您能回答它,以便我们可以看到如何在您最喜欢的工具包中完成它吗?这是一个难题,我想看看您如何在该工具包中解决它。 - Bryan Oakley
显示剩余8条评论
2个回答

37

我很高兴地告诉你,实际上可以做到,并且只需几行代码即可实现(我不知道其他工具包是否那么容易):

from Tkinter import *
import os

root = Tk()
termf = Frame(root, height=400, width=500)

termf.pack(fill=BOTH, expand=YES)
wid = termf.winfo_id()
os.system('xterm -into %d -geometry 40x20 -sb &' % wid)

root.mainloop()

之前的问题是使用了错误的wid函数。


2
有没有办法使帧自动适应xterm窗口的大小(而不是硬编码高度=400,宽度=500)? - gnr
3
我仍不确定这段代码在Mac OS X上是否按照预期运行,因为我的情况是一个Python shell窗口在xterm上启动,没有其他反应(仅当我指定完整的xterm路径时),我看不出你想用这段代码实现什么... 这段代码应该做什么?对我来说,模拟器并没有被插入到框架中,而是独立启动,并且空的tkinter窗口同时运行。 - nbro
异形:我刚在我的旧Macbook上测试了一下,见http://imgur.com/SOXfyMb。我仍然使用Snow Leopard,我不知道它是否适用于更新的版本,但应该可以。 - alessandro
如果您希望xterm随着框架大小调整而调整大小,则必须添加回调函数:https://dev59.com/y1kS5IYBdhLWcg3wHTJy#59807248 - Tinmarino
8
这个回答中的代码不具备可移植性。例如,在Windows系统中,没有xterm命令(该命令是必需的)。 - martineau

0

亚历山德罗在五小时前已经报告了他认为足够的模型。对于未来搜索到此项的人,我将记录一些我所知道的背景事实:

布赖恩能够指出window_id()和winfo_id()之间的差异,并纠正其他人在编写各种工具包时所犯的错误,这是幸运的。

对我来说,stackoverflow与更专业的频道相比有趣。在这种情况下,Tkinter邮件列表http://mail.python.org/pipermail/tkinter-discuss/2011-September/002968.html迅速而准确地回答了这个问题。

Tkinter可能会是至少一些月球软件的改进。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接