我有一些文本在输出中有点连续(在实际应用程序中大约每两秒钟出现一次)。
当print
进入终端时,无论我保持运行循环多长时间,一切都很好。
然而,当引导打印到wx
帧时,打印动作本身进行得很好,这里没有问题,但是如果我保持运行循环超过10-20个周期,我不再能够正常关闭窗口(在这个例子中鼠标或Ctrl+F4,但如果我构造一个显式的退出事件菜单也是一样的)。线程中的动作停止了,但是应用程序挂起了——它只能由操作系统(在我的情况下是Windows)用"强制关闭/等待程序响应"对话框关闭。但是,当终端窗口处于焦点时,可以使用Ctrl+C立即关闭它。看起来好像有什么东西填满了太多的文本并锁定了关闭进程。
在多行wxTextCtrl
窗口上与WriteText
或AppendText
一起发生,或者与下面测试代码中的SetLabel一起发生。
在这个测试中,如果我在启动后几乎立即关闭wx窗口,它关闭得很好。如果我继续运行循环更长时间(或者注释掉两个time.sleep()
行),那么无论何时尝试关闭窗口,挂起都会成功。
我在这里错过了什么?(有什么东西要冲吗?)
edit嗯,这个问题可能与"线程安全方法"有关,正如这里简要描述的那样。我会在那个方向做一些测试,必须找出wx.CallAfter
, wx.CallLater
或wx.PostEvent
的正确用法。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import wx
import time
import threading
class TestFrame(wx.Frame):
def __init__(self, *args, **kwds):
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.sometext = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY)
self.thread = None
self.alive = threading.Event()
self.__set_properties()
self.__do_layout()
self.__attach_events()
self.StartThread()
def __set_properties(self):
self.SetTitle("test")
def __do_layout(self):
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.sometext, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL, 0)
self.SetSizer(sizer)
sizer.Fit(self)
self.Layout()
def __attach_events(self):
self.Bind(wx.EVT_CLOSE, self.OnClose)
def OnClose(self, event):
""" stop & close on system window close """
self.StopThread()
self.Destroy()
def StartThread(self):
""" start the thread """
self.thread = threading.Thread(target=self.TestThread)
self.thread.setDaemon(1)
self.alive.set()
self.thread.start()
def StopThread(self):
""" stop the thread, wait util it is finished """
if self.thread is not None:
self.alive.clear()
self.thread.join()
self.thread = None
def TestThread(self):
""" main thread """
while self.alive.isSet():
self.sometext.SetLabel("Hello")
time.sleep(0.5)
self.sometext.SetLabel("Python")
time.sleep(0.5)
class MyApp(wx.App):
def OnInit(self):
wx.InitAllImageHandlers()
frame = TestFrame(None, -1, "")
self.SetTopWindow(frame)
frame.Show(1)
return 1
if __name__ == "__main__":
app = MyApp(0)
app.MainLoop()
我已经用AppendtText改变了每个SetLabal。我不知道为什么,但是SetLabel函数不能正确地为我工作。
几秒钟后,应用程序将停止工作。这是我的错误输出:
(python:14099): Pango-CRITICAL **: pango_layout_get_iter: assertion 'PANGO_IS_LAYOUT (layout)' failed
Segmentation fault
之后,我使用CallAfter函数http://wiki.wxpython.org/CallAfter应用程序开始为我正确工作。我的TestThread版本:
def TestThread(self):
""" main thread """
while self.alive.isSet():
wx.CallAfter(self.sometext.AppendText, "Hello")
time.sleep(0.5)
wx.CallAfter(self.sometext.AppendText, "Python")
time.sleep(0.5)
wx.CallAfter(self.sometext.Clear)
我希望这对你有帮助。