简体   繁体   中英

Printing line by line output to GUI in Python

I want to print my stdout to GUI in python. I am using Tkinter. This is what I is working for me

def get_likes_button():
    output = subprocess.Popen(['python', "getLikes.py"], stdout=subprocess.PIPE)
    s1 = output.stdout.read()
    text.delete("1.0",END)
    text.insert(INSERT,s1)

But, I am getting the whole output at once. What I want is that the GUI should print the output iteratively just like it prints on terminal.

So, I tried this, but it gave me an error on clicking the button

def get_likes_button():
    text.delete("1.0",END)
    with subprocess.Popen(['python', "getLikes.py"], stdout=subprocess.PIPE) as output:
        s1 = output.stdout.read()
        text.insert(INSERT,s1)

The error is

Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1489, in __call__
return self.func(*args)
File "gui.py", line 88, in get_likes_button
with subprocess.Popen(['python', "getLikes.py"], stdout=subprocess.PIPE) as output:
AttributeError: __exit__

Can you please suggest me what to do?

Popen does not support context managers (ie with ) hence the error. But also note that there is no practical difference between the 2 versions of your code.

You could instead read line by line:

def get_likes_button():
    child = subprocess.Popen(['python', 'getLikes.py'], stdout=subprocess.PIPE)
    text.delete("1.0",END)
    for line in iter(child.stdout.readline, ''):
        text.insert(INSERT, line)
    child.stdout.close()
    child.wait()

The line for line in iter(child.stdout.readline, ''): is used to work around the buffering that would be experienced if the loop had been for line in child.stdout: .


Update

Try revising the code as follows:

def get_likes_button():
    child = subprocess.Popen(['python', '-u', 'getLikes.py'], stdout=subprocess.PIPE)
    text.delete("1.0",END)
    for line in iter(child.stdout.readline, ''):
        text.insert(INSERT, line)
        text.see(END)
        text.update_idletasks()
    child.stdout.close()
    child.wait()

The changes are:

  1. Use the -u python option for unbuffered output in the child,
  2. Call text.see(END) to scroll the text window to the bottom after each insert,
  3. Call text.update_idletasks() to give Tkinter a chance to update the text widget.

This might help to avoid using threads, but the one down side of this is that the rest of the GUI will be unresponsive while your callback is executing. That might be acceptable if your child process is short lived, perhaps not if the child runs for an extended period - it depends on your application.

I don't think subprocess.Popen can be used within with clause. I think check_output is what you need:

output = subprocess.check_output(['python', 'getLikes.py'])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM