2017-08-14 20 views
0

我有一个功能,运行一些密集的命令,所以我做了Spinner类,这只是一个简单的窗口出现与wx.Gauge部件在加载期间脉冲。wxPython:框架类加载几个命令后,它被称为

问题是,在Run中调用时,窗口在初始化几秒后才出现 - self.TriangulatePoints()实际上在窗口出现之前完成。事实上,如果我不注释掉load.End()(它关闭窗口),Spinner实例将出现并立即消失。

我认为这与线程有关,程序继续运行,而Spinner启动。是这样吗?如果是这样,你可以暂停Run()的进展,直到Spinner窗口出现?

还应该注意的是,调用Spinner(...)后运行time.sleep(n)在程序序列中不会改变,它会出现在屏幕上。

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

什么错误使用wx.SplashScreen? – Igor

+0

好的,这是一个更大的基于wx的应用程序的一小部分 - 当按下工具栏按钮时,“运行”功能实际上被调用。由于我在主'wx.Frame'中有内容,所以重要的是我有一个外部窗口出现。 –

+1

https://wiki.wxpython.org/LongRunningTasks –

回答

0

通过在load.Update('...')之后立即加上wx.Yield(),我可以解决问题。

我发现通过后罗宾邓恩(@RobinDunn),wxPython中的原始作者之一,wrote in a Google group溶液:

作为弥提到的各种屈服函数本质上是 嵌套事件循环,其读取并从 事件队列调度未决事件。当队列为空时,yield函数返回。

原因[wx.Yield()]解决了您看到的问题,因为您的长运行任务阻止控制回到主事件 循环,因此您的自定义小部件的绘画事件将仅停留在 队列,直到长时间运行的任务完成,并且允许控制 返回到主循环。增加收益率可以使这些事件得到更早处理,但是当长期运行任务最终运行时,您可能仍然会遇到问题,因为在此期间需要处理任何新事件(例如,用户单击了 取消按钮)仍然必须等到LRT完成。

使用yield函数时要注意的另一个问题是它可能导致意外的递归。例如,您有一个LRT ,它定期调用收益率,以便处理事件,但发生的事件之一是其事件处理程序再次启动LRT 的事件之一。

所以平时最好是使用一些其他的方式,以防止阻断 事件而运行的轻轨,如分解成被从EVT_IDLE处理程序运行块 ,或使用一个线程。

1

似乎有没有在你展示的代码的任何线程,所以真的不明白为什么你觉得这有什么关系线程。恰恰相反,事实上:AFAICS这是由于而不是使用线程。您应该在工作线程中运行长时间运行(“密集”)代码,然后在UI中正常工作并正确显示。

您不能阻止主UI线程的任何重要的时间,并仍然期望UI能够正确更新。

+0

同意,但这仍不能解释情况。我有一系列命令“A-B-C-D”。发生的事情是命令以这个顺序执行:'B-C-D-A',其中'A'是新的'wx.Frame'的初始化。我想知道为什么当我调用它时没有出现'A',而是在最终执行之前执行其他任务。 –

+1

如果你使用的是wxGTK,那么显示(实现)一个新帧是一个涉及一些延迟的复杂操作。只要事件循环正在运行,通常无关紧要。 –

+0

嗯,我是在64位的MacOS,我相信默认为wxOSX /可可,不wxGTK –