0

我是 WX 的新手,所以我决定制作一个程序,它会根据外部输入定期在屏幕上写出一行文本。该程序的基础包含一个基本窗口,其中多行文本控件覆盖整个窗口。我在框架中拥有的唯一其他方法是打印出该方法listen_event获得的任何内容作为多行 TextCtrl 的新行。就是这样,作为证明,代码如下:

class Frame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None,
            title = 'Program',
            size = (640, 480),
            style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.MINIMIZE_BOX)
        panel = wx.Panel(self)
        self.textArea = wx.TextCtrl(parent = panel,
            id = -1,
            pos = (0, 0),
            size = (-1, -1),
            style = wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_AUTO_URL)

    def listen_event(self, data):
        self.textArea.AppendText(data)

从另一个线程定期调用监听事件。一切似乎都很好,该程序可以正常工作,但是,每隔一段时间(比我想要的更多)我都会收到大量让我想起 ObjectiveC 错误消息的转储:

2013-06-21 20:11:47.820 Python[85638:420b] An uncaught exception was raised
2013-06-21 20:11:47.821 Python[85638:420b] NSMutableRLEArray replaceObjectsInRange:withObject:length:: Out of bounds
2013-06-21 20:11:47.824 Python[85638:420b] (
    0   CoreFoundation                      0x00007fff92e2bf56 __exceptionPreprocess + 198
    1   libobjc.A.dylib                     0x00007fff8fc0bd5e objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff92e2bd8a +[NSException raise:format:arguments:] + 106
    3   CoreFoundation                      0x00007fff92e2bd14 +[NSException raise:format:] + 116
    4   Foundation                          0x00007fff8fe93b20 -[NSMutableRLEArray replaceObjectsInRange:withObject:length:] + 132
    5   AppKit                              0x00007fff8d3e33f8 -[NSLayoutManager addTemporaryAttribute:value:forCharacterRange:] + 500
    6   AppKit                              0x00007fff8d7f9716 -[NSTextView _markTextEditedForRange:] + 1025
    7   AppKit                              0x00007fff8d7f8392 -[NSTextView insertText:replacementRange:] + 2400
    8   AppKit                              0x00007fff8d7f7a25 -[NSTextView insertText:] + 320
    9   libwx_osx_cocoau-2.9.4.0.0.dylib    0x0000000101953b71 _ZN19wxNSTextViewControl9WriteTextERK8wxString + 257
    10  libwx_osx_cocoau-2.9.4.0.0.dylib    0x00000001018bfb53 _ZN11wxTextEntry9WriteTextERK8wxString + 67
    11  _core_.so                           0x00000001014dec57 _wrap_TextEntryBase_AppendText + 199
    12  Python                              0x00000001000c1112 PyEval_EvalFrameEx + 22626
    13  Python                              0x00000001000c2d29 PyEval_EvalCodeEx + 2137
    14  Python                              0x00000001000c0b6a PyEval_EvalFrameEx + 21178
    15  Python                              0x00000001000c1ebe PyEval_EvalFrameEx + 26126
    16  Python                              0x00000001000c1ebe PyEval_EvalFrameEx + 26126
    17  Python                              0x00000001000c1ebe PyEval_EvalFrameEx + 26126
    18  Python                              0x00000001000c1ebe PyEval_EvalFrameEx + 26126
    19  Python                              0x00000001000c2d29 PyEval_EvalCodeEx + 2137
    20  Python                              0x00000001000c0b6a PyEval_EvalFrameEx + 21178
    21  Python                              0x00000001000c1ebe PyEval_EvalFrameEx + 26126
    22  Python                              0x00000001000c2d29 PyEval_EvalCodeEx + 2137
    23  Python                              0x000000010003da80 function_call + 176
    24  Python                              0x000000010000c5e2 PyObject_Call + 98
    25  Python                              0x000000010001ebcb instancemethod_call + 363
    26  Python                              0x000000010000c5e2 PyObject_Call + 98
    27  Python                              0x00000001000ba5f7 PyEval_CallObjectWithKeywords + 87
    28  Python                              0x0000000100100a63 t_bootstrap + 67
    29  libsystem_c.dylib                   0x00007fff933008bf _pthread_start + 335
    30  libsystem_c.dylib                   0x00007fff93303b75 thread_start + 13
)
2013-06-21 20:11:47.825 Python[85638:420b] *** Terminating app due to uncaught exception 'NSRangeException', reason: 'NSMutableRLEArray replaceObjectsInRange:withObject:length:: Out of bounds'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff92e2bf56 __exceptionPreprocess + 198
    1   libobjc.A.dylib                     0x00007fff8fc0bd5e objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff92e2bd8a +[NSException raise:format:arguments:] + 106
    3   CoreFoundation                      0x00007fff92e2bd14 +[NSException raise:format:] + 116
    4   Foundation                          0x00007fff8fe93b20 -[NSMutableRLEArray replaceObjectsInRange:withObject:length:] + 132
    5   AppKit                              0x00007fff8d3e33f8 -[NSLayoutManager addTemporaryAttribute:value:forCharacterRange:] + 500
    6   AppKit                              0x00007fff8d7f9716 -[NSTextView _markTextEditedForRange:] + 1025
    7   AppKit                              0x00007fff8d7f8392 -[NSTextView insertText:replacementRange:] + 2400
    8   AppKit                              0x00007fff8d7f7a25 -[NSTextView insertText:] + 320
    9   libwx_osx_cocoau-2.9.4.0.0.dylib    0x0000000101953b71 _ZN19wxNSTextViewControl9WriteTextERK8wxString + 257
    10  libwx_osx_cocoau-2.9.4.0.0.dylib    0x00000001018bfb53 _ZN11wxTextEntry9WriteTextERK8wxString + 67
    11  _core_.so                           0x00000001014dec57 _wrap_TextEntryBase_AppendText + 199
    12  Python                              0x00000001000c1112 PyEval_EvalFrameEx + 22626
    13  Python                              0x00000001000c2d29 PyEval_EvalCodeEx + 2137
    14  Python                              0x00000001000c0b6a PyEval_EvalFrameEx + 21178
    15  Python                              0x00000001000c1ebe PyEval_EvalFrameEx + 26126
    16  Python                              0x00000001000c1ebe PyEval_EvalFrameEx + 26126
    17  Python                              0x00000001000c1ebe PyEval_EvalFrameEx + 26126
    18  Python                              0x00000001000c1ebe PyEval_EvalFrameEx + 26126
    19  Python                              0x00000001000c2d29 PyEval_EvalCodeEx + 2137
    20  Python                              0x00000001000c0b6a PyEval_EvalFrameEx + 21178
    21  Python                              0x00000001000c1ebe PyEval_EvalFrameEx + 26126
    22  Python                              0x00000001000c2d29 PyEval_EvalCodeEx + 2137
    23  Python                              0x000000010003da80 function_call + 176
    24  Python                              0x000000010000c5e2 PyObject_Call + 98
    25  Python                              0x000000010001ebcb instancemethod_call + 363
    26  Python                              0x000000010000c5e2 PyObject_Call + 98
    27  Python                              0x00000001000ba5f7 PyEval_CallObjectWithKeywords + 87
    28  Python                              0x0000000100100a63 t_bootstrap + 67
    29  libsystem_c.dylib                   0x00007fff933008bf _pthread_start + 335
    30  libsystem_c.dylib                   0x00007fff93303b75 thread_start + 13
)
terminate called throwing an exception

是什么赋予了?我找不到这些错误的韵律或原因。有时它连续为一对夫妇工作,然后崩溃。有时它会在第一次运行时崩溃。我是否错误地实现了文本控制框?

4

2 回答 2

2

这可能是也可能不是您崩溃的原因,但如果肯定会导致崩溃,并且它们很可能正是您所看到的那种崩溃(有时它有效,有时它失败,有时它工作一段时间然后突然失败,即使没有任何可见的变化......)。

您不能从其他线程调用对 UI 对象进行操作的方法。每次self.textArea.AppendText从另一个线程调用时,都有可能崩溃——或者更有趣的是,破坏内存或其他资源导致以后崩溃。

有几种不同的方法:

  • 用于PostEvent为主 UI 线程排队事件(在事件处理程序中使用实际的 UI 更改代码)。
  • 使用CallAfterCallLater调度要在主 UI 线程上调用的函数(在该函数中使用实际的 UI 更改代码)。
  • 使用pubsub框架。
  • 使用一些external-to-wx 机制(例如,从threading模块、管道或其他)向主UI 线程发出信号。
  • 以上不止一项。

(在幕后,CallAfter是一个包装器PostEvent,并且CallLater是一个计时器加号的包装器CallAfter,并且计时器和threading都是相同本机线程API的包装器,依此类推,所以这并没有看起来那么多不同的可能性...... )


无论如何,对您的代码最微不足道的更改是:

def listen_event(self, data):
    wx.CallAfter(self.textArea.AppendText, data)

最重要的是,您违反了多线程编程的第一条规则:共享可变对象只能在锁定下访问。

我不认为这会导致您的问题。由于self在创建后将永远不会更改属性,并且(假设您使用的是 CPython 或其他带有 GIL 的 Python 实现)没有其他任何非原子性的事情会影响您,因此您将在这里侥幸逃脱。但是如果你不明白为什么你的代码(除了wx调用)是线程安全的,你就不应该指望它。

于 2013-06-22T00:38:49.093 回答
0

当我运行我的程序时,我遇到了同样的问题。如果您可以查看我的代码并建议进行一些更改,这将非常有帮助。我在这里发布了我的问题: Application crashed while given input to wxPython GUI。谢谢你的帮助。

于 2014-07-18T06:34:55.603 回答