我是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)
从另一个线程定期调用listen事件。一切似乎都没问题,程序可行,但是,每隔一段时间(比我想的更频繁)我得到一个大量的转储让我想起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
是什么给出的?我找不到这些错误的押韵或原因。有时它适用于连续几对,然后崩溃。有时它会在第一时间崩溃。我是否错误地实现了文本控制框?
答案 0 :(得分:2)
这可能是或可能不是你的崩溃的原因,但如果肯定会导致崩溃,并且它们可能正是你所看到的那种崩溃(有时候它会起作用,有时会失败,有时会起作用)一段时间然后突然失败,即使没有任何可见的变化......)。
您无法从其他线程调用对UI对象进行操作的方法。每次从另一个线程调用self.textArea.AppendText
时,都有可能崩溃 - 或者更有趣,破坏内存或其他资源,导致以后崩溃。
有几种不同的方法:
PostEvent
为主UI线程排队事件(在事件处理程序中使用实际的UI更改代码)。CallAfter
或CallLater
来安排在主UI线程上调用函数(在该函数中使用实际的UI更改代码)。pubsub
框架。threading
模块,或管道或其他)来表示主UI线程。(在幕后,CallAfter
是PostEvent
的包装,CallLater
是计时器加CallAfter
的包装,计时器和threading
两者都是围绕相同的本机线程API的包装器,依此类推,所以这并不像看起来那么多不同的可能性......)
无论如何,对代码的最微不足道的改变是:
def listen_event(self, data):
wx.CallAfter(self.textArea.AppendText, data)
最重要的是,您违反了多线程编程的第一条规则:共享可变对象只能在锁定下访问。
我不认为这会导致你的问题。因为self
在创建之后永远不会改变属性,并且(假设你正在使用CPython,或者其他一些带有GIL的Python实现),没有任何其他可能会以非原子方式发生可能影响你的东西,你将会离开在这里。但是,如果您不理解为什么您的代码(wx
调用除外)是线程安全的,那么您不应该依赖它。
答案 1 :(得分:0)
我运行程序时遇到了同样的问题。如果您能查看我的代码并建议进行一些更改,将会非常有帮助。我在这里发布了我的问题: Application crashed while giving input to wxPython GUI。谢谢你的帮助。