2010-01-12 95 views
3

一直在想,現在這個天:更新wx.gauge沒有while循環

我有這樣一個基本的wxPython程序:

from MyModule import * 

class Form(wx.Panel): 
    def __init__(self, parent, id): 
    self.gauge = wx.Gauge(...) 
    ... 
    def ButtonClick(self, event): 
    proc = LongProcess() 
    while (LongProcess): 
     self.gauge.SetValue(LongProcess.status) 
     wx.Yield() 

其中進口的MyModule.py:

from threading import * 

class LongProcess(self): 
    def __init__(self): 
    Thread.__init__(self) 
    self.start() 
    def run(self): 
    for i in range(100): 
     Do_something() 
     self.status = i 

如預期的那樣,根據值LongProcess.status更新儀表。但是while循環似乎並不合適,因爲整個程序使用100%cpu負載,因爲它不斷檢查狀態(不奇怪,tho)。有什麼方法可以在沒有每秒數百萬次的情況下將狀態發送回「母親程序」?

回答

8

您可以從非GUI線程實例化自定義事件,並將wx.PostEvent事件返回到GUI線程。這是一個線程安全的操作。我的使用情況通常像這樣工作:

  • 開始工作線程 - 自定義事件「開始行動」
  • 開始處理
  • 後回事件的進展更新「生產線15000 435解析」
  • 等。

然後我綁定自定義事件來更新對話框或textctrl/log或其他。這很容易做到。如果您希望我可以發佈一些測試用例的示例代碼,那麼我在寫這些東西時寫了一段時間。

- 編輯:

好這裏的一些代碼,第一絲扣例如:

#!usr/bin/env python 

import wx 
import threading 
import Queue 
import random 
import time 

TextEventType = wx.NewEventType() 
EVT_THREAD_TEXT_EVENT = wx.PyEventBinder(TextEventType, 1) 

global_queue = Queue.Queue() 

def threadStart(numthrds, queue, window): 
    for i in range(numthrds): 
     i = TextThread(queue, window) 

class TextThread(threading.Thread): 
    def __init__(self, queue, output_window): 
     threading.Thread.__init__(self) 
     self.inqueue = queue 
     self.output_window = output_window 
     self.start() 


    def run(self): 
     word = self.inqueue.get() 
     self.setName(word.upper()) 
     wait = random.randrange(1, 10) 
     time.sleep(wait) 
     msg = 'Thread: ' + self.getName() + '--wait= ' + str(wait) + ' ' + word 
     evt = NewTextEvent(TextEventType, -1) 
     evt.setText(msg) 
     wx.PostEvent(self.output_window, evt) #post EVT_THREAD_TEXT_EVENT 
     #self.inqueue.task_done() #may not need this if non-blocking 



class NewTextEvent(wx.PyCommandEvent): 
    def __init__(self, evtType, id): 
     wx.PyCommandEvent.__init__(self, evtType, id) 

     self.msg = '' 

    def setText(self, text): 
     self.msg = text 

    def getText(self): 
     return self.msg 

class TextFrame(wx.Frame): 
    def __init__(self, parent, id, *args, **kwargs): 
     wx.Frame.__init__(self, parent, id, *args, **kwargs) 
     self.queue = Queue.Queue() 
     framesizer = wx.BoxSizer(wx.VERTICAL) 
     self.panel = ThreadPanel(self, wx.ID_ANY) 
     framesizer.Add(self.panel, 0, wx.EXPAND) 
     self.SetSizerAndFit(framesizer) 

     self.Bind(EVT_THREAD_TEXT_EVENT, self.OnThreadText) 

    def OnThreadText(self, evt): 
     msg = evt.getText() 
     self.panel.out_tc.AppendText(msg + '\n') 

class ThreadPanel(wx.Panel): 
    def __init__(self, parent, id, *args, **kwargs): 
     wx.Panel.__init__(self, parent, *args, **kwargs) 
     vsizer = wx.BoxSizer(wx.VERTICAL) 
     self.wordtc = wx.TextCtrl(self, id=wx.ID_ANY, value='', size=(350, -1)) 
     self.inst_text = wx.StaticText(self, wx.ID_ANY, 
      label='Enter a list of space-separated words') 
     self.out_tc = wx.TextCtrl(self, id=wx.ID_ANY, size=(350, 300), 
      value='', style=wx.TE_MULTILINE) 
     self.start_button = wx.Button(self, wx.ID_ANY, label='Start Threads') 

     vsizer.Add(self.inst_text, 0, wx.ALIGN_LEFT) 
     vsizer.Add(self.wordtc, 0, wx.EXPAND) 
     vsizer.Add(self.start_button) 
     vsizer.Add((100,100)) 
     vsizer.Add(self.out_tc, 0, wx.EXPAND) 
     self.SetSizer(vsizer) 
     self.Bind(wx.EVT_BUTTON, self.OnStartButton, self.start_button) 

    def OnStartButton(self, evt): 
     self.out_tc.Clear() 
     text = self.wordtc.GetValue() 
     self.wordtc.Clear() 
     if not text.count(','): 
      text = text.split(' ') 
     num_thrds = len(text) 
     for word in text: 
      word = word.strip() 
      self.GetParent().queue.put(word) 
     threadStart(num_thrds, self.GetParent().queue, self.GetParent()) 




if __name__ == "__main__": 
    app = wx.App() 
    frame = TextFrame(None, wx.ID_ANY, 'Thread test') 
    frame.Show()  
    app.MainLoop() 

的和自定義事件第二,更簡單的例子:

#!usr/bin/env python 

import wx 
import random 

colorEventType = wx.NewEventType() 
EVT_COLOR_EVENT = wx.PyEventBinder(colorEventType, 1) 

class ButtonPanel(wx.Panel): 
    def __init__(self, parent, *args, **kwargs): 
     wx.Panel.__init__(self, parent, *args, **kwargs) 

     vsizer = wx.BoxSizer(wx.VERTICAL) 
     self.rstbutt = wx.Button(self, wx.ID_ANY, label='Restore') 
     self.rstbutt.Disable() 
     self.Bind(wx.EVT_BUTTON, self.OnButt, self.rstbutt) 
     vsizer.Add(self.rstbutt, 0, wx.ALIGN_CENTER) 
     vsizer.Add((500,150), 0) 
     self.SetSizer(vsizer) 

    def OnButt(self, evt): 
     self.SetBackgroundColour(wx.NullColor) 
     self.GetParent().Refresh() 
     self.rstbutt.Disable() 

class ColorEvent(wx.PyCommandEvent): 
    def __init__(self, evtType, id): 
     wx.PyCommandEvent.__init__(self, evtType, id) 
     self.color = None 

    def SetMyColor(self, color): 
     self.color = color 

    def GetMyColor(self): 
     return self.color 

class MainFrame(wx.Frame): 
    def __init__(self, parent, *args, **kwargs): 
     wx.Frame.__init__(self, parent, *args, **kwargs) 
     framesizer = wx.BoxSizer(wx.VERTICAL) 
     self.panel = ButtonPanel(self, wx.ID_ANY) 
     framesizer.Add(self.panel, 1, wx.EXPAND) 

     menubar = wx.MenuBar() 
     filemenu = wx.Menu() 
     menuquit = filemenu.Append(wx.ID_ANY, '&Quit') 
     menubar.Append(filemenu, 'File') 
     colormenu = wx.Menu() 
     switch = colormenu.Append(wx.ID_ANY, '&Switch Color') 
     menubar.Append(colormenu, '&Color') 
     self.SetMenuBar(menubar) 

     self.Bind(wx.EVT_MENU, self.OnQuit, menuquit) 
     self.Bind(wx.EVT_MENU, self.OnColor, switch) 
     self.Bind(EVT_COLOR_EVENT, self.ColorSwitch) 
     self.SetSizerAndFit(framesizer) 

    def OnQuit(self, evt): 
     self.Close() 

    def OnColor(self, evt): 
     colevt = ColorEvent(colorEventType, -1) 
     colors = ['red', 'green', 'blue', 'white', 'black', 'pink', 
      (106, 90, 205), #slate blue 
      (64, 224, 208), #turquoise 
      ] 
     choice = random.choice(colors) 
     colevt.SetMyColor(choice) 
     self.GetEventHandler().ProcessEvent(colevt) 
     #evt.Skip() 

    def ColorSwitch(self, evt): 
     color = evt.GetMyColor() 
     #print(color) 
     self.panel.SetBackgroundColour(color) 
     self.Refresh() 
     self.panel.rstbutt.Enable() 



if __name__ == "__main__": 
    app = wx.App() 
    frame = MainFrame(None, wx.ID_ANY, title="Change Panel Color Custom Event") 
    frame.Show(True) 

    app.MainLoop() 
+0

謝謝您的回答。我明白了,但我還沒有和PostEvent合作過,示例代碼會有很大的幫助。 – 2010-01-12 21:27:29