[Python编程(第4版)].(Programming.Python.4th.Edition).Mark.Lutz.文字版

(yzsuai) #1

pass
else:
if not line: # stop loop at end-of-file
output.write(term) # else display next line
return
output.write(line)
root.after(250, lambda: consumer(output, root, term))


def redirectedGuiShellCmd(command, root):
input = os.popen(command, 'r') # start non-GUI program
output = GuiOutput(root)
thread.start_new_thread(producer, (input,)) # start reader thread
consumer(output, root)


if name == 'main':
win = Tk()
redirectedGuiShellCmd('python -u pipe-nongui.py', win)
win.mainloop()


As usual, we use a queue here to avoid updating the GUI except in the main thread.
Note that we didn’t need a thread or queue in the prior section’s socket example, just
because we’re able to poll a socket to see whether it has data without blocking; an
after timer loop was enough. For a shell-command pipe, though, a thread is an easy
way to avoid blocking.


When run, this program’s self-test code creates a ScrolledText window that displays
the current date and time sent from the pipes-nongui.py script in Example 10-27. In
fact, its window is identical to that of the prior versions (see Figure 10-15). The window
is updated with a new line every two seconds because that’s how often the spawned
pipes-nongui script prints a message to stdout.


Note how the producer thread calls readline() to load just one line at a time. We can’t
use input calls that consume the entire stream all at once (e.g., read(), readlines()),
because such calls would not return until the program exits and sends end-of-file. The
read(N) call would work to grab one piece of the output as well, but we assume that
the output stream is text here. Also notice that the -u unbuffered stream flag is used
here again, to get output as it is produced; without it, output won’t show up in the GUI
at all because it is buffered in the spawned program (try it yourself).


Sockets and pipes: Compare and contrast


Let’s see how we’ve done. This script is similar in spirit to what we did in Exam-
ple 10-28. Because of the way its code is structured, though, Example 10-29 has a major
advantage: because input calls are spawned off in a thread this time, the GUI is com-
pletely responsive. Window moves, resizes, and so forth, happen immediately because
the GUI is not blocked while waiting for the next output from the non-GUI program.
The combination of a pipe, thread, and queue works wonders here—the GUI need not
wait for the spawned program, and the spawned thread need not update the GUI itself.


More Ways to Add GUIs to Non-GUI Code | 659
Free download pdf