[pygtk] Show command output (new IEs4Linux GUI)
Internet Explorer Linux
ies4linux at gmail.com
Fri Dec 8 14:38:40 WST 2006
Hey, thank you guys!
I decided to do it with threads. See how it looks now:
tatanka.com.br/ies4linux/news
On 12/1/06, Edward Catmur <ed at catmur.co.uk> wrote:
>
> On Thu, 2006-11-30 at 04:14 -0200, Internet Explorer Linux wrote:
> > I'm working on a pygtk user interface to my script. My GUI configures
> > some things and run an executable (IEs4linux installer, written in
> > bash). I need to open some kind of window to show the installer
> > output.
> >
> > I tried with TextView, but I don't know how to make it non-blocking. I
> > tried with Threads, but it waits until installer finishes to show the
> > output on TextView. I searched on Google and got some pages talking
> > about this (even with "solutions"), but I could not make it work.
>
> You need to tie the fd (from your child's stdout) into the GLib
> mainloop. The way to do this is to make it nonblocking and add a watch
> on it; your watch callback then adds the data that appears on the fd to
> the textview.
>
> Obviously threads would work as well, but if you can write your
> application single-threaded it'll save a load of heartache debugging
> races when you get the reentrancy and locking wrong.
>
> Here's a fairly comprehensive example; I put it together to demonstrate
> watching the output of a DVD burning script, but it's obviously
> applicable to your situation.
>
> Ed
>
> #!/usr/bin/env python
>
> import gobject, gtk, sys, os, fcntl
>
> def get_stock_icons(widget, id):
> set =3D widget.style.lookup_icon_set(id)
> return map(lambda x: set.render_icon(widget.style,
> gtk.TEXT_DIR_NONE,
> gtk.STATE_NORMAL, x, widget, None), set.get_sizes())
>
> class LogWindow:
> def input_callback(self, source, condition):
> if condition & (gobject.IO_HUP):
> self.eof()
> return False
> try:
> while True:
> line =3D source.readline()
> print line.__repr__()
> if line =3D=3D '':
> self.eof()
> return False
> self.append_text(line)
> except IOError:
> pass
> return True
>
> def eof(self):
> self.ok.set_sensitive(True)
> self.cancel.set_sensitive(False)
> self.warn.hide()
>
> def append_text(self, text):
> end_iter =3D self.buffer.get_end_iter()
> endmark =3D self.buffer.create_mark(None, end_iter)
> self.textview.move_mark_onscreen(endmark)
> at_end =3D self.buffer.get_iter_at_mark
> (endmark).equal(end_iter)
> self.buffer.insert(end_iter, text)
> if at_end:
> endmark =3D self.buffer.create_mark(None, end_ite=
r)
> self.textview.scroll_mark_onscreen(endmark)
>
> def delete_event(self, widget, data =3D None):
> self.warn.show_all()
> return True
>
> def destroy(self, widget, data =3D None):
> gtk.main_quit()
>
> def expanded(self, widget, param_spec, data =3D None):
> if widget.get_expanded():
> self.window.set_resizable(True)
> else:
> self.window.set_resizable(False)
>
> def response(self, widget, response_id, data =3D None):
> if response_id =3D=3D gtk.RESPONSE_OK:
> self.destroy(widget)
> elif response_id =3D=3D gtk.RESPONSE_CANCEL:
> self.delete_event(widget)
>
> def __init__(self, source):
> # make source non-blocking
> fd =3D source.fileno()
> fcntl.fcntl(fd, fcntl.F_SETFL,
> fcntl.fcntl(fd, fcntl.F_GETFL) |
> os.O_NONBLOCK)
> gobject.io_add_watch(source,
> gobject.IO_IN | gobject.IO_PRI |
> gobject.IO_HUP,
> self.input_callback)
>
> window =3D gtk.MessageDialog(buttons =3D gtk.BUTTONS_OK_C=
ANCEL
> )
> for x in window.action_area.get_children():
> if x.get_use_stock():
> if x.get_label() =3D=3D gtk.STOCK_OK:
> self.ok =3D x
> elif x.get_label() =3D=3D gtk.STOCK_CANCE=
L:
> self.cancel =3D x
> self.ok.set_sensitive(False)
> window.set_markup(
> """<b>The files are being burnt to DVD.</b>
>
> Please wait while the process completes.""")
> window.set_title("Burning DVD")
> gtk.window_set_default_icon_list(
> *get_stock_icons(window, gtk.STOCK_CDROM))
> window.connect("delete_event", self.delete_event)
> window.connect("destroy", self.destroy)
> window.connect("response", self.response)
> self.window =3D window
>
> warn =3D gtk.MessageDialog(parent =3D window,
> flags =3D gtk.DIALOG_MODAL,
> type =3D gtk.MESSAGE_WARNING,
> buttons =3D gtk.BUTTONS_CANCEL)
> warn.add_button("Abort DVD", gtk.RESPONSE_CLOSE)
> warn.set_markup("""<b>Are you sure you want to abort
> burning the
> DVD?</b>
>
> If the burning process has already started, the DVD will be ruined.""")
> def warn_response(widget, response_id, data =3D None):
> if response_id =3D=3D gtk.RESPONSE_CANCEL:
> warn.hide()
> elif response_id =3D=3D gtk.RESPONSE_CLOSE:
> self.returnError =3D 1
> self.destroy(widget, True)
> warn.connect("response", warn_response)
> self.warn =3D warn
>
> expander =3D gtk.Expander("_Display detailed output")
> expander.set_use_underline(True)
> expander.connect("notify::expanded", self.expanded)
> window.vbox.pack_start(expander, True, True, 0)
>
> textview =3D gtk.TextView()
> textview.set_editable(False)
> self.textview =3D textview
> self.buffer =3D self.textview.get_buffer()
> scroll =3D gtk.ScrolledWindow()
> scroll.add(self.textview)
> scroll.set_size_request(0, 100)
> expander.add(scroll)
>
> window.show_all()
>
> def main(self):
> self.returnError =3D 0
> gtk.main()
> return self.returnError
>
> if __name__ =3D=3D "__main__":
> sys.exit(LogWindow(sys.stdin).main())
>
> _______________________________________________
> pygtk mailing list pygtk at daa.com.au
> http://www.daa.com.au/mailman/listinfo/pygtk
> Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.daa.com.au/pipermail/pygtk/attachments/20061208/bab03e24/at=
tachment.htm
More information about the pygtk
mailing list