2017-08-14 23 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 –