我有一个运行一些密集命令的函数,所以我创建了一个Spinner
类,它只是一个带有wx.Gauge
小部件的简单窗口,在加载过程中会发出脉冲。
问题是,在Run
中调用时,窗口在初始化后几秒钟才会出现 - self.TriangulatePoints()
实际上在窗口出现之前完成。实际上,如果我没有评论load.End()
(关闭窗口),Spinner
实例将会出现并立即消失。
我认为这与线程有关,程序会在Spinner
启动时继续运行。是这样的吗?如果是这样,您可以暂停Run()
的进度直到Spinner
窗口出现吗?
还应该注意,调用time.sleep(n)
后运行Spinner(...)
在屏幕上显示的程序序列中不会改变。
def Run(self, event):
gis.points_packed = False
gis.triangulated = False
load = Spinner(self, style=wx.DEFAULT_FRAME_STYLE & (~wx.CLOSE_BOX) & (~wx.MAXIMIZE_BOX) ^ (wx.RESIZE_BORDER) & (~wx.MINIMIZE_BOX))
load.Update('Circle packing points...')
gis.boundary(infile=gis.loaded_boundary)
load.Pulse()
self.GetPoints(None, show=False)
load.Update("Triangulating nodes...")
self.TriangulatePoints(None, show=True)
load.End()
########################################################
class Spinner(wx.Frame):
def __init__(self, *args, **kwds):
super(Spinner, self).__init__(*args, **kwds)
self.SetSize((300,80))
self.SetTitle('Loading')
process = "Loading..."
self.font = wx.Font(pointSize = 12, family = wx.DEFAULT,
style = wx.NORMAL, weight = wx.BOLD,
faceName = 'Arial')
self.process_txt = wx.StaticText(self, -1, process)
self.process_txt.SetFont(self.font)
self.progress = wx.Gauge(self, id=-1, range=100, pos=(10,30), size=(280,15), name="Loading")
self.Update(process)
self.Centre()
self.Show(True)
def End(self):
self.Close(True)
def Update(self,txt):
dc = wx.ScreenDC()
dc.SetFont(self.font)
tsize = dc.GetTextExtent(txt)
self.process_txt.SetPosition((300/2-tsize[0]/2,10))
self.process_txt.SetLabel(txt)
self.progress.Pulse()
def Pulse(self):
self.progress.Pulse()
答案 0 :(得分:1)
在您显示的代码中似乎没有任何线程,所以它真的不清楚为什么您认为这与线程有任何关系。恰恰相反,事实上:AFAICS这是由于不使用线程。您应该在工作线程中运行长时间运行("密集型")代码,然后在UI中正常工作并显示。
您无法在任何非常重要的时间内阻止主要的UI线程,并且仍然希望UI能够正确更新。
答案 1 :(得分:0)
在wx.Yield()
之后立即添加load.Update('...')
,我就能解决问题。
我通过一篇文章找到了解决方案:Robin Dunn(@RobinDunn),wxPython的原始作者之一,wrote in a Google group:
正如弥迦所说,各种屈服函数基本上都是一个 嵌套事件循环,用于从中读取和分派待处理事件 事件队列。当队列为空时,yield函数返回。
[wx.Yield()]修复你遇到的问题的原因是你的长期 正在运行的任务阻止控件返回主事件 循环,因此您的自定义小部件的绘制事件将位于其中 队列,直到长时间运行的任务完成并且控制为 允许返回主循环。添加产量允许那些 事件要尽快处理,但你可能仍然有问题 长时间运行的任务最终会运行,因为任何新的事件 需要在此期间进行处理(例如,用户单击a 取消按钮)仍然需要等到LRT完成。
使用yield函数时要注意的另一个问题是它 可能会导致意外的递归。例如,你有LRT 定期调用yield以便可以处理事件,但是其中一个 发生的事件是其事件处理程序启动LRT的事件 试。
所以通常最好使用其他方法来防止阻塞 运行LRT时的事件,例如将其分解为块 从EVT_IDLE处理程序或使用线程运行。