33

I want to embed a terminal in my main Tkinter window. I would like to have a sub window where a terminal (Bash based terminal) would run. I would like also to be able to let my program interact with the terminal, at least I would like to read the current working directory and/or set it.

I don't know if it is really impossible. I was able to do it in the past with Perl/Tk, so maybe it can be replicated here.

The code I used then was something like:

$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 &"); 

where $mw was the main Tk window.

Of course, I completely agree with Bryan: though I never programmed with a GUI library before, my program (rather large, a kind of wiki) is running very well, with a surprisingly low amount of code devoted to the GUI itself.

I tried translating this Perl code, but I'm stumbling on the ID problem.

The only place where I found some reference to a way to extract the ID from Tkinter is in Effbot, but when I use it, I get 'AttributeError: Frame instance has no attribute 'window_id', so there must be something wrong:

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);  
Community
  • 1
  • 1
alessandro
  • 3,838
  • 8
  • 40
  • 59
  • 1
    You can embed vte in a pygtk app, but I don't know of a similar thing in tkinter. Any particular reason you are using tkinter? – Keith Aug 31 '11 at 06:45
  • 1
    just the fact that I found it easier to learn than other widgets! – alessandro Aug 31 '11 at 08:23
  • Invest the time in learning pygtk, it has more of a future. Or PyQT, if you prefer. ;-) – Keith Aug 31 '11 at 09:03
  • Have you tried converting that perl code to python? More specifically, have you tried embedding xterm in a frame? Tkinter is the same underlying tk library as perl/tk so it should work equally as well. – Bryan Oakley Aug 31 '11 at 11:09
  • 2
    @Keith: why do you say pygtk has more of a future? Tkinter has been around a _long_ time and is part of the python core. I don't see it being taken out of python for a very, very long time. – Bryan Oakley Aug 31 '11 at 11:10
  • You want to use the common method `winfo_id()` rather than `window_id`. BTW: when researching documentation, the definitive source of information is the tcl/tk documentation at tcl.tk/man. You have to do a little mental translation from tcl to tkinter syntax but most translations are obvious (for example, instead of the `winfo id` tk command you would use the `winfo_id` method). – Bryan Oakley Aug 31 '11 at 14:18
  • @bryan as others have also pointed out, you can only get so far with tkinter. If you want to do more, and also have a look-and-feel that is at least close to the native (or common) desktops then you should probably be using one of the others anyway. They are really not much harder, anyway. – Keith Aug 31 '11 at 19:44
  • 4
    @Keith: I think you are wrong with the "only get so far" comment. I've created some very complex, successful commercial apps based of of Tk (admittedly, with tcl/tk rather than python/tkinter). The fact is, many, many applications don't need anything Tkinter doesn't provide, especially when you consider the addition of the ttk widgets in the most recent versions of Tkinter. – Bryan Oakley Aug 31 '11 at 20:53
  • @bryan Fair enough. But you can't embed a terminal emulator. ;-) – Keith Aug 31 '11 at 23:34
  • 1
    @Keith: you seem to imply that this is possible with pygtk. This question (http://stackoverflow.com/questions/5993390/embed-interactive-shell-vte-in-a-pygtk-gui-to-manipulate-its-own-widgets) asks how to do that in pygtk - could you answer it so we could see how to do it in your favorite toolkit? It's a tough problem to solve and I'd like to see how you do it in that toolkit. – Bryan Oakley Sep 01 '11 at 11:00
  • more on this: http://groups.google.com/group/comp.lang.python/msg/b3d69494a9d680ee – noob oddy Sep 02 '11 at 04:21
  • @Dhaivat Pandya: if you read the question you'll see the perl is some existing code he used for illustrative purposes. The OP wants the python/tkinter equivalent to that perl code. – Bryan Oakley Sep 07 '11 at 11:11
  • see also [tkterminal](https://github.com/Saadmairaj/tkterminal), a Terminal widget for Tkinter – milahu Apr 06 '22 at 02:35

2 Answers2

37

I am happy to say that it is in fact possible to do it, and you can do it with just a few lines of code (I don't know if it is so easy with other toolkits):

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()

The problem before was to use the wrong function for wid.

nbro
  • 15,395
  • 32
  • 113
  • 196
alessandro
  • 3,838
  • 8
  • 40
  • 59
  • 2
    Is there any way to make the Frame automatically fit to the size of the xterm window (instead of hard-coding the height=400, width=500) – gnr Sep 12 '14 at 17:24
  • 3
    I am still not convinced if this code does what it is supposed to do on a Mac OS X, because what happens to me is that a Python shell section is started on `xterm` and nothing else (and only if I specify the whole path to `xterm`), I am not seeing what you want to achieve with this code... what does this code is supposed to do? For me the emulator is not inserted in the Frame, but it starts independently and an empty tkinter window runs at the same time.. – nbro May 13 '15 at 21:16
  • Xenomorph: I just tested it on my old Macbook, see http://imgur.com/SOXfyMb . I'm still with Snow Leopard, I dont know if it works for newer versions but it should – alessandro May 15 '15 at 15:38
  • If you want the xterm to be resized with the frame, you must add a callback: https://stackoverflow.com/a/59807248/2544873 – Tinmarino Jan 19 '20 at 06:23
  • 8
    The code in this answer is not portable. Windows, for example, does not have an `xterm` command (which it requires). – martineau Jan 22 '21 at 16:19
0

Alessandro already reported five hours before what he regards as an adequate model. For those who come across this item during future searches, I'll record a few more background facts I know:

It was fortunate that Bryan was here to draw attention to the differences between window_id() and winfo_id(), and to counter the errors others made in writing about various toolkits.

It's interesting to me how stackoverflow compares to more specialized channels. In this case, the Tkinter mailing list http://mail.python.org/pipermail/tkinter-discuss/2011-September/002968.html swiftly and accurately responded to the question.

Tkinter would be an improvement on at least some of the moon-rocket software.

Cameron Laird
  • 1,067
  • 5
  • 9