wxPython:frame类在调用后加载几个命令

时间:2017-08-14 23:38:00

标签: python wxpython wxwidgets

我有一个运行一些密集命令的函数,所以我创建了一个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()

2 个答案:

答案 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处理程序或使用线程运行。