how do i use "tkinter.createfilehandler" with a regular c program?

J

Jo Schambach

I am trying to write a GUI with tkinter that displays the stdout from a
regular C/C++ program in a text widget.
The idea i was trying to use was as follows:

1) use "popen" to execute the C/C++ program
2) then use "tkinter.createfilehandler" to create a callback that would
be called when the C/C++ program creates output on stdout.

Somehow, I can't get this to work. here is what I have tried so far:

import sys,os
from Tkinter import *

root = Tk()
mainFrame = Frame(root)
textBox = Text(mainFrame)
textBox.pack(fill=BOTH, expand=YES)
mainFrame.pack(fill=BOTH, expand=YES)

fh = os.popen('/homes/jschamba/tof/pcan/pcanloop')

def readfh(filehandle, stateMask):
global textBox
newText = filehandle.read()
textBox.insert(END, newText)

tkinter.createfilehandler(fh, tkinter.READABLE, readfh)
root.mainloop()


I don't see any of the stdout from my program appear in the textbox.

Does anyone have a short example that I could use as an inspiration for
this task?

I guess what my ultimate goal would be is to create something similar to
the "expectk" call "expect_background", which does exactly what i just
described, i.e. wait for output from a shell/C/C++ program and then do
something in response to this output like insert it into a text widget.
In expect, the following program seems to work:

#!/usr/bin/expectk -f

# disable terminal output
log_user 0

spawn -noecho /homes/jschamba/tof/pcan/pcanloop
set shell $spawn_id
text .shell -relief sunken -bd 1 -width 90 -height 24 -yscrollcommand
{.scroll set}
scrollbar .scroll -command {.shell yview}
pack .scroll -side right -fill y
pack .shell -side bottom -expand true -fill both

expect_background {
-i $shell -re "\[^\x0d]+" {
.shell insert end $expect_out(0,string)
.shell yview -pickplace insert
}
}


Jo
--
Dr Joachim Schambach
The University of Texas at Austin
Department of Physics
1 University Station C1600
Austin, Texas 78712-0264, USA
Phone: (512) 471-1303; FAX: (814) 295-5111
e-mail: (e-mail address removed)
 
J

jepler

Compared to your program, I
* Made sure that the slave program actually flushed its stdout buffers
* didn't call read(), which will by default continue reading until
it reaches EOF, not merely read the available data

#!/usr/bin/env python
import sys, time, Tkinter, itertools, _tkinter, os

if '-slave' in sys.argv:
for i in itertools.count():
time.sleep(1)
print "This is a line of output:", i
sys.stdout.flush()
raise SystemExit

root = Tkinter.Tk()
root.wm_withdraw()

fh = os.popen('%s -slave' % sys.argv[0])

def reader(*args):
line = fh.readline()
if not line:
print "EOF from slave"
raise SystemExit
print "from slave: %r" % line

_tkinter.createfilehandler(fh, Tkinter.READABLE, reader)
root.mainloop()

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFDePR9Jd01MZaTXX0RAk6SAKCdYh2mbnbRk7Dc6Q9hImCuiVrfXwCfdlgS
bVtpMT08YIylmRqKlPCZV6U=
=YPSK
-----END PGP SIGNATURE-----
 
J

Jim Segrave

I am trying to write a GUI with tkinter that displays the stdout from a
regular C/C++ program in a text widget.
The idea i was trying to use was as follows:

1) use "popen" to execute the C/C++ program
2) then use "tkinter.createfilehandler" to create a callback that would
be called when the C/C++ program creates output on stdout.

Somehow, I can't get this to work. here is what I have tried so far:

import sys,os
from Tkinter import *

root = Tk()
mainFrame = Frame(root)
textBox = Text(mainFrame)
textBox.pack(fill=BOTH, expand=YES)
mainFrame.pack(fill=BOTH, expand=YES)

fh = os.popen('/homes/jschamba/tof/pcan/pcanloop')

def readfh(filehandle, stateMask):
global textBox
newText = filehandle.read()
textBox.insert(END, newText)

tkinter.createfilehandler(fh, tkinter.READABLE, readfh)
root.mainloop()

Changingfilehandle.read() to filehandle.readline() and running a
separate output generator, this seems to work, although the Text
widget fills rapidly:

========= test generator - creates a pipe and writes the time once/second
#!/usr/local/bin/python
import os, time

try:
pipe = os.mkfifo('./pipe', 0660)
except OSError, (errno):
if errno == 17:
pass

fh = open('./pipe', 'w')
rh = open('./pipe', 'r') # keep the pipe having a reader
while True:
fh.write("%s\n" % time.asctime(time.localtime()))
fh.flush()
time.sleep(1)

========== read the output and put in a Text widget:
#!/usr/bin/python
import sys,os
from Tkinter import *

root = Tk()
mainFrame = Frame(root)
textBox = Text(mainFrame)
textBox.pack(fill=BOTH, expand=YES)
mainFrame.pack(fill=BOTH, expand=YES)

fh = os.popen('/bin/cat /tmp/pipe', 'r', 1)

def readfh(filehandle, stateMask):
global textBox
newText = filehandle.readline()
textBox.insert(END, newText)

tkinter.createfilehandler(fh, tkinter.READABLE, readfh)
root.mainloop()
 
J

Jo Schambach

Thanks, that seems to work.
maybe one more question on this subject:

how can i use the callback function to the "createfilehandler" call from
within a class?
in other words, what would be the signature of the callback function, if
I made it a member of a class?
The documentation says that the callback is called with the arguments:
callback(filehandle, stateMask)
but a class member function always has the "self" argument as is first
argument. So would the syntax be:

class GUI:
def __init__:
.....

def filehandlerCallback(self, filehandle, stateMask):
....


Jo
Compared to your program, I
* Made sure that the slave program actually flushed its stdout buffers
* didn't call read(), which will by default continue reading until
it reaches EOF, not merely read the available data

#!/usr/bin/env python
import sys, time, Tkinter, itertools, _tkinter, os

if '-slave' in sys.argv:
for i in itertools.count():
time.sleep(1)
print "This is a line of output:", i
sys.stdout.flush()
raise SystemExit

root = Tkinter.Tk()
root.wm_withdraw()

fh = os.popen('%s -slave' % sys.argv[0])

def reader(*args):
line = fh.readline()
if not line:
print "EOF from slave"
raise SystemExit
print "from slave: %r" % line

_tkinter.createfilehandler(fh, Tkinter.READABLE, reader)
root.mainloop()


--
Dr Joachim Schambach
The University of Texas at Austin
Department of Physics
1 University Station C1600
Austin, Texas 78712-0264, USA
Phone: (512) 471-1303; FAX: (814) 295-5111
e-mail: (e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top