【问题标题】:wxPython: CallAfter(AppendText,string) does not print entire stringwxPython:CallAfter(AppendText,string) 不打印整个字符串
【发布时间】:2011-04-05 22:06:02
【问题描述】:

我有一个循环接收套接字数据并打印它的线程:

def post(self):
    while True:
        try:
            data = pickle.loads(self.sock.recv(1024))
            print data[0] % tuple(data[1])
        except (socket.error, EOFError): 
            break

然后我有一个 GUI,可以将标准输出重定向到 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 来诱导它,看看是否是导致它的原因,但即使我什么都不做,这些“部分打印”也会时不时出现.怎么回事?

【问题讨论】:

  • 我应该补充一点,如果我使用“打印数据”,GUI 会在“部分打印”之后附加 \n,但如果我使用 sys.stdout.write(data+'\n') 它不会追加新行。我的打印调用和 CallAfter 的 AppendText 调用之间的数据是否以某种方式损坏? Fenikso 在第 30 行和第 63 行显示它始终如一地发生,这似乎也很奇怪。
  • 现在我假设问题是数据来自另一个线程并且以某种方式被损坏。不确定 AppendText 是如何工作的,但可能在打印过程中,post 线程将 data = 设置为下一个 sock.recv()

标签: multithreading wxpython appendtext


【解决方案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

我尝试使用延迟和互斥锁/锁,但似乎我还没有找到为什么会发生这种情况。

【讨论】:

  • 感谢您提供可运行的示例。我不确定套接字是否只是接收到不完整的数据,但我想你已经证明不是这种情况。
  • @Shaunak Amin - 是的,总是一样的。或者它们不在大约 10% 的运行中的任何位置。真的很奇怪。
  • 我在帖子线程中添加了一个 li.append(data) 并发布了第 30 行和第 63 行的数据:每行的数据都以“”结尾,所以问题出在 CallAfter 或AppendText 没有完整打印字符串...我只是不知道为什么它会在之后继续打印而不会引发错误或打印跟踪,如果它以某种方式中止打印字符串似乎应该这样。
  • 当我在没有线程的情况下调用 post() 时,问题不会发生,所以我认为线程在 CallAfter(AppendText,string) 完成之前设置了 data = sock.recv() 。通常打印比 sock.recv() 快,但偶尔不会。奇怪的是它总是发生在同一行。
  • 我只是给你打勾,因为你花时间调查,谢谢你的帮助。
猜你喜欢
  • 1970-01-01
  • 2011-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-14
  • 1970-01-01
  • 2014-05-28
  • 2018-11-25
相关资源
最近更新 更多