Reputation: 8257
I've been searching for an hour, and can't find a definitive answer to this one.
I'm trying to write a wxPython GUI app, that has a button which launches a command-line tool (all on Windows). The tool takes about 5 minutes to run, and produces output as it goes along.
I'd like the GUI to have some sort of text window showing the output as it happens. I'd also like killing the GUI to terminate the command-line process.
I've looked at threads and Popen, and don't seem to be able to work out the correct connection between them all to make this work. Can anyone point me at a sensible example?
Upvotes: 2
Views: 1932
Reputation: 3087
I do this exact thing in wxPython in my GooeyPi app. It runs a pyInstaller command and captures the output line by line in a textctrl.
In the main app frame, there's a button that calls OnSubmit
:
def OnSubmit(self, e):
...
# this is just a list of what to run on the command line, something like [python, pyinstaller.py, myscript.py, --someflag, --someother flag]
flags = util.getflags(self.fbb.GetValue())
for line in self.CallInstaller(flags): # generator function that yields a line
self.txtresults.AppendText(line) # which is output to the txtresults widget here
and CallInstaller
does the actual running of the command, yielding a line as well as running wx.Yield() so the screen doesn't freeze up too badly. You could move this to its own thread, but I haven't bothered.
def CallInstaller(self, flags):
# simple subprocess.Popen call, outputs both stdout and stderr to pipe
p = subprocess.Popen(flags, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while(True):
retcode = p.poll() # waits for a return code, until we get one..
line = p.stdout.readline() # we get any output
wx.Yield() # we give the GUI a chance to breathe
yield line # and we yield a line
if(retcode is not None): # if we get a retcode, the loop ends, hooray!
yield ("Pyinstaller returned return code: {}".format(retcode))
break
Upvotes: 2
Reputation: 33111
I wrote up an article where I did something along the lines that you're talking about. I needed to run ping and traceroute and capture their output in real-time. Here's the article: http://www.blog.pythonlibrary.org/2010/06/05/python-running-ping-traceroute-and-more/
Basically you need to redirect stdout to a text control and then do something like this:
proc = subprocess.Popen("ping %s" % ip, shell=True,
stdout=subprocess.PIPE)
line = proc.stdout.readline()
print line.strip()
As you can see, I use subprocess to start ping and read its stdout. Then I use the strip() command to remove extra whitespace from the beginning and end of the line before I print it out. When you do the print, it gets redirected to the text control.
Upvotes: 2