wxPython: CallAfter (AppendText, строка) не печатает всю строку - PullRequest
0 голосов
/ 06 апреля 2011

У меня есть поток, который зацикливает получение данных сокета и распечатывает их:

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 Ответ

1 голос
/ 06 апреля 2011

Это не реальный ответ, просто способ воспроизвести проблему:

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

Я пытался поиграть с задержками и мьютексами / блокировками, но, похоже, я пока не понял, почему это происходит.

...