Reputation: 3682
I've got the countdown.exe file (source code of this file is below). When this files is executed he write in console every second text. I start execution of this file when my GUI python app is executed:
self.countdown_process = subprocess.Popen("countdown.exe", shell=True, stdout=subprocess.PIPE)
I redirect stdout in subprocess.PIPE and start thread out_thread
which read stdout of this process and add to TextCtrl:
out_thread = OutTextThread(self.countdown_process.stdout, self.AddText)
out_thread.start()
This is the full code of my python app:
import os
import sys
import wx
import subprocess, threading
class MyFrame(wx.Frame):
def __init__(self):
super(MyFrame, self).__init__(None)
self._init_ctrls()
def _init_ctrls(self):
self.OutText = wx.TextCtrl(id=wx.NewId(), value='', name='OutText',
parent=self, pos=wx.Point(0, 0),
size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2)
self.OutText.AppendText("Starting process...\n")
self.OutText.AppendText("Waiting 10 seconds...\n")
self.countdown_process = subprocess.Popen("countdown.exe", shell = True, stdout=subprocess.PIPE)
out_thread = OutTextThread(self.countdown_process.stdout, self.AddText)
out_thread.start()
def AddText(self, text):
self.OutText.AppendText(text)
class OutTextThread(threading.Thread):
def __init__(self, std_out, cb):
super(OutTextThread, self).__init__()
self.std_out = std_out
self.cb = cb
def run(self):
text = None
while text != '':
text = self.std_out.readline()
self.cb(text)
if __name__ == '__main__':
app = wx.App(False)
frame = MyFrame()
frame.Show(True)
app.MainLoop()
The C++ code of countdown.exe is simple:
#include <stdio.h>
#include <time.h>
void wait ( int seconds )
{
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
}
int main ()
{
int n;
printf ("Starting countdown...\n");
for (n=10; n>0; n--)
{
printf ("%d\n",n);
wait (1);
}
printf ("FIRE!!!\n");
return 0;
}
But i have some problem. I start my python app and i must wait 10 second and only 10 seconds the stdout of countdown.exe is written in TextCtrl as you can see on picture below:
I want the realtime writing the stdout of countdown.exe in TextCtrl (self.OutText). How I can do this?
I tried using wx.CallAfter in AddText method:
def AddText(self, text):
wx.CallAfter(self.OutText.AppendText, text)
but it's useless.
Upvotes: 0
Views: 1603
Reputation: 33111
You cannot call wxPython methods directly from a thread. So the line
self.cb(text)
won't work. But if you put that into a threadsafe method, such as wx.CallAfter, then it should work. See the following links:
I also wrote a tutorial on redirecting stuff from stdout to a text control here:
Upvotes: 1