6

I am developing a program, in which I want a window that will display the output thrown by the terminal (like a package manager does ). For example, if I give the install command, the installation process should be outptutted to my window and not the terminal. Is there a way to do this in python Gtk?

I am using an Ubuntu 13.04.

2

3 Answers 3

12
+50

If you are on Linux (as you state), something like this should work:

import gtk 
import gobject
import pango
import os
from subprocess import Popen, PIPE
import fcntl

wnd = gtk.Window()
wnd.set_default_size(400, 400)
wnd.connect("destroy", gtk.main_quit)
textview = gtk.TextView()
fontdesc = pango.FontDescription("monospace")
textview.modify_font(fontdesc)
scroll = gtk.ScrolledWindow()
scroll.add(textview)
exp = gtk.Expander("Details")
exp.add(scroll)
wnd.add(exp)
wnd.show_all()
sub_proc = Popen("ping -c 10 localhost", stdout=PIPE, shell=True)
sub_outp = ""


def non_block_read(output):
    fd = output.fileno()
    fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
    try:
        return output.read().decode("utf-8")
    except:
        return ''


def update_terminal():
    textview.get_buffer().insert_at_cursor(non_block_read(sub_proc.stdout))
    return sub_proc.poll() is None

gobject.timeout_add(100, update_terminal)
gtk.main()

The nonblocking read idea is from here.

Using a Label to display the text:

import gtk 
import gobject
import os
from subprocess import Popen, PIPE
import fcntl

wnd = gtk.Window()
wnd.set_default_size(400, 400)
wnd.connect("destroy", gtk.main_quit)
label = gtk.Label()
label.set_alignment(0, 0)
wnd.add(label)
wnd.show_all()
sub_proc = Popen("ping -c 10 localhost", stdout=PIPE, shell=True)
sub_outp = ""


def non_block_read(output):
    ''' even in a thread, a normal read with block until the buffer is full '''
    fd = output.fileno()
    fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
    try:
        return output.read().decode("utf-8")
    except:
        return ''


def update_terminal():
    label.set_text(label.get_text() + non_block_read(sub_proc.stdout))
    return sub_proc.poll() is None

gobject.timeout_add(100, update_terminal)
gtk.main()
Sign up to request clarification or add additional context in comments.

4 Comments

This updates it to a textview. What if i want to send it to a Label?
Because a textview looks some what ugly
Kind of. But the actual output i want is , Like what happens in synaptic package manager. The output that it shows when you install through it
As far as I can tell, synaptic uses a TextView inside a ScrolledWindow and an Expander to show/hide it. Also, a fixed width font is used. I updated the first example accordingly. Of course, you can further refine the font and display styles to suit your needs.
1

I've been trying to do this and really struggling. I couldn't get the first example working and moved quickly onto the 2nd.

Using the 2nd example above (Using Label to display text) and found that this works fine with Python 2.7 but I'm trying to use Python3 and some things just don't work.

I struggled for ages trying to convert to Python3 and had to change some of the imports and change gtk to Gtk which got it mostly working but the thing that really stumped me was due to Python3 using utf-8 codes. I finally got it working by modifying "the non_block_read" function changing the returned text from utf-8 to string and coping with the return None case.

I hope this helps.

For completeness I attach my working code:-

#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')

from gi.repository import Gtk
from gi.repository import GObject

import os
from subprocess import Popen, PIPE
import fcntl

wnd = Gtk.Window()
wnd.set_default_size(400, 400)
wnd.connect("destroy", Gtk.main_quit)
label = Gtk.Label()
label.set_alignment(0, 0)
wnd.add(label)
wnd.show_all()
sub_proc = Popen("ping -c 10 localhost", stdout=PIPE, shell=True)
sub_outp = ""


def non_block_read(output):
    ''' even in a thread, a normal read with block until the buffer is full '''
    fd = output.fileno()
    fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
    op = output.read()
    if op == None:
        return ''
    return op.decode('utf-8')



def update_terminal():
    label.set_text(label.get_text() + non_block_read(sub_proc.stdout))
    return sub_proc.poll() is None

GObject.timeout_add(100, update_terminal)
Gtk.main()

Comments

0

You can use the subprocess module and the os module to get back the terminal output.You can check this question.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.