Python 更新wx.gauge而不使用while循环

Python 更新wx.gauge而不使用while循环,python,wxpython,Python,Wxpython,几天来,我一直在想: 我有一个基本的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.gau

几天来,我一直在想:

我有一个基本的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,这并不奇怪)。是否有任何方法可以将状态发送回“母亲计划”,而不必每秒执行数百万次

您可以从非GUI线程实例化自定义事件,并将它们返回到GUI线程。这是一个线程安全操作。我的用例通常是这样工作的:

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()
  • 启动工作线程-自定义事件“启动操作”
  • 开始处理
  • Post events back updating progress“解析了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()

谢谢你的回答。我明白这个想法,但我还没有使用PostEvent,示例代码将非常有帮助。