wxPython: CallAfter(AppendText, строка) не печатает всю строку
У меня есть поток, который зацикливает получение данных сокета и печать его:
def post(self):
while True:
try:
data = pickle.loads(self.sock.recv(1024))
print data[0] % tuple(data[1])
except (socket.error, EOFError):
break
Затем у меня есть графический интерфейс, который перенаправляет стандартный вывод в textctrl, например, так:
import wx
import sys
import threading
class Redirect:
def __init__(self, ctrl):
self.out = ctrl
def write(self, string):
wx.CallAfter(self.out.AppendText,string)
class GUI(wx.Frame):
def __init__(self, parent):
self.monitor = wx.TextCtrl(self, wx.ID_ANY, \
style = wx.TE_MULTILINE | wx.TE_READONLY)
redir = Redirect(self.monitor)
sys.stdout = redir
self.sizer = BoxSizer(wx.VERTICAL)
self.sizer.Add(self.monitor, 1, wx.GROW | wx.ALL)
self.SetSizer(self.sizer)
self.Show(True)
if __name__ == "__main__":
app = wx.App(False)
frame = GUI(None)
app.MainLoop()
У меня также есть второй textctrl, который принимает ввод (пропущено для простоты). Проблема в том, что иногда CallAfter(AppendText,string) не распечатывает всю строку. Это очень редко, но иногда печать просто резко останавливается в середине строки, после чего печатается следующая строка (и приложение продолжает печатать строки, когда они получены, как будто ничего не произошло).
Я понятия не имею, что вызывает это поведение, я пытался вызвать его, набрав во втором textctrl, чтобы увидеть, если это вызывает, но даже если я ничего не делаю, эти "частичные отпечатки" появляются время от времени. В чем дело?
1 ответ
Это не реальный ответ, просто способ воспроизвести проблему:
import wx
import sys
import threading
def post():
a = 0
for stop in range(100):
a = (a + 1) % 10
data = str(a) * 1000 + " <END>"
print(data)
for i, line in enumerate(frame.monitor.Value.split("\n")[:-1]):
if not line.endswith(" <END>"):
print("Invalid line %d" % (i+1))
class Redirect:
def __init__(self, ctrl):
self.out = ctrl
def write(self, string):
wx.CallAfter(self.out.AppendText, string)
class GUI(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
self.monitor = wx.TextCtrl(self, wx.ID_ANY, style = wx.TE_MULTILINE | wx.TE_READONLY)
redir = Redirect(self.monitor)
sys.stdout = redir
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.monitor, 1, wx.GROW | wx.ALL)
self.SetSizer(self.sizer)
self.Show(True)
if __name__ == "__main__":
app = wx.App(False)
frame = GUI(None)
t = threading.Thread(target=post)
t.start()
app.MainLoop()
При запуске на моей установке, я получаю (обычно, не всегда):
Invalid line 30
Invalid line 63
Я пытался играть с задержками и мьютексами / блокировками, но, похоже, я пока не понял, почему это происходит.