Version 27 of How to embed a non-Tk GUI into a Tk frame

Updated 2011-08-14 03:30:52 by RLE

Purpose: to collect tips, suggestions, questions, and examples where developers have written tcl/tk code that wraps around an existing GUI window.

In particular, I'm interested in hearing people talk about doing this under the X Window System.

Has anyone an example, for instance, of embedding perhaps an xterm inside a tcl/tk frame?

AMG: Try this.

 exec xterm -into [scan [winfo id .] %x] &

But Tk has no knowledge of the xterm stowing away in its toplevel, and the xterm doesn't seem to know much about its parent window, so there's no geometry propagation whatsoever. Hey, what do you expect from one line of code!? ;^)

tonytraductor I've noted that, using the above technique, closing the parent windows makes the xterm disappear, but does not kill the xterm process, which must then be killed manually (using a sysmon or with a new terminal on the command line), unless, of course, one includes something more like

 set ::pid [exec xterm -into ...]
 exec kill -9 $::pid; exit

I'm interested in learning how to embed other applications, such as an mplayer video screen. Mplayer -into does not work.

sg man mplayer. Seek for a keyword... Okay, embed, for example. Aha, there is -wid option in MP's options set. I'm trying a line...

 exec /usr/bin/mplayer -wid [winfo id .f] /usr/share/example-content/Experience\ ubuntu.ogg &

LV From a recent discussion on comp.lang.tcl regarding a request for code so that an application could let the user use a personal preference of editor.

 package require Tk
 frame .f -container yes
 pack .f -fill both -expand yes
 # Solaris users should note that neither /usr/openwin/bin/xterm or
 #   /opt/sfw/bin/xterm apparently are new enough to have the -into.
 #   so you are resigned to do without or to get a newer version of xterm
 exec xterm -into [ expr [winfo id .f ]] -e $env(EDITOR) & 

See BLT's 'container' command. From the man page...

The container widget lets you embed an X11 window from a foreign application into your Tk application. The foreign window is reparented inside of the widget. You can then place and arrange the container just as you would any Tk widget.

- Marty Backe -- 24 Nov 2004


See the page about the TkXext extension at http://wiki.tcl.tk/2116 It's a compiled Tcl/Tk extension. I think it only works on X11 on Unix/Linux. But you can embed non-Tcl/Tk windows inside a Tk frame with it. I used it in a project on Slackware 7.2 Linux with Tcl/Tk 8.4 and it worked well.


LV Has anyone used the frame -container option to do this sort of thing?


Googie Pretty easy example is to embed mplayer into Tk frame or toplevel window. Mplayer has -wid option, which orders mplayer to embed in X11 window with given ident. We can resolve ident of our toplevel or frame by wm.


Rildo Pragana - For a multimedia window, you may even crop and pan its shown media, with Tk'k place geometry manager, see Crop multimedia with tk's place.


PT 16-Dec-2009: Here is a more concrete example of embedding mplayer into a Tk window to display a webcam video source. This one is tied to the first video source and 640x480 but the window can be resized fine. Mplayer has a -slave option which tells the program to read commands from standard input. Using this we can tell it when to terminate nicely and have it take screenshots on demand.

 # showcam.tcl - Copyright (C) 2009 Pat Thoyts <[email protected]>
 #
 #        Demonstration of mplayer embedding into a Tk application.
 #
 # mplayer can be embedded in a Tk window if it is passed the window id
 # of a frame. We can then control it via its slave mode over standard
 # input and output. There are a number of possible commands but here
 # we use 'screenshot' to have it save a snapshot to a unique filename
 # and reply on the pipe with the filename. We can read the filename
 # and delete the file to suck captures into Tk images.
 #
 package require Tk
 variable uid     ; if {![info exists uid]} {set uid 0}
 variable mplayer ; if {![info exists mplayer]} {set mplayer ""}
 
 proc Screenshot {} {
     variable mplayer
     if {$mplayer ne ""} { puts $mplayer "screenshot 0" }
 }
 
 proc OnScreenshot {filename} {
     variable uid
     set image [image create photo -file $filename]
     file delete $filename
     set dlg [toplevel .dlg_$image -class Dialog]
     wm title $dlg "Screenshot #[incr uid]"
     wm transient $dlg .
     pack [label $dlg.image -image $image] -fill both
 }
 
 # Read lines from mplayer stdout
 proc ReadPipe {chan} {
     set d [read $chan]
     foreach line [split $d \n] {
         set line [string trim $line]
         if {[regexp {^\*\*\* screenshot '(.*?)' \*\*\*} $line -> filename]} {
             # delay to permit the file to appear
             after 250 [list OnScreenshot $filename]
         }
     }
     if {[eof $chan]} {
         fileevent $chan readable {}
         close $chan
         variable mplayer ""
     }
 }
 
 proc Embed {w {device /dev/video0}} {
     set r [catch {
         set height 640
         set width 480
         set cmd mplayer
         lappend cmd tv:// -quiet -slave -idle \
             -tv driver=v4l2:width=$width:height=$height:device=$device \
             -vf screenshot -fps 15 -wid [winfo id $w]
         set pipe [open |$cmd r+]
         fconfigure $pipe -blocking 0 -buffering line
         fileevent $pipe readable [list ReadPipe $pipe]
         variable mplayer $pipe
     } err]
 
     if {$r} {
         tk_messageBox -icon error -title "Show camera error" \
             -message $err
     }
 }
 
 proc Exit {} {
     variable mplayer
     if {[info exists mplayer] && $mplayer ne ""} {
         catch {puts $mplayer quit}
         return [after idle [list after 10 [list Exit]]]
     }
     set ::forever 1
 }
 
 proc Main {} {
     wm title . "Show camera"
     wm protocol . WM_DELETE_WINDOW [list Exit]
     wm withdraw .
 
     option add *tearOff false
     . configure -menu [menu .menu]
     .menu add cascade -label File -menu [menu .menu.file]
     .menu.file add command -label Screenshot -command Screenshot
     .menu.file add command -label Exit -command Exit
 
     frame .video -width 640 -height 480 
 
     grid .video  - -sticky news
     grid rowconfigure . 0 -weight 1
     grid columnconfigure . 0 -weight 1
 
     # add the video once the window exists and is mapped
     bind .video <Map> {
         bind %W <Map> {}
         Embed %W
     }
 
     wm deiconify .
 }
 
 if {!$tcl_interactive} {
     if {![info exists initialized]} {
         set initialized 1
         set r [catch [linsert $argv 0 Main] err]
         vwait ::forever   
         if {$r} {
             tk_messageBox -icon error -title "Show camera" \
                 -message $err
         }
         exit $r
     }
 }