【问题标题】:wxPython threading wxGaugewxPython 线程 wxGauge
【发布时间】:2023-06-10 08:50:01
【问题描述】:

我正在尝试使用 wxPython 学习线程,因此我尝试使这个简单的示例工作,但似乎进度条更新发生在“长过程”完成之后。谁能告诉我为什么这不起作用?

#!/usr/bin/env python
import time
import wx
from wx.lib.pubsub import Publisher as pub


class Window(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, title="wxGauge")
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.gauge = wx.Gauge(self, range=10)
        self.btn = wx.Button(self, label="Start process")
        self.sizer.Add(self.gauge)
        self.sizer.Add(self.btn)
        self.SetSizerAndFit(self.sizer)
        pub.subscribe(self.update, "update")
        self.btn.Bind(wx.EVT_BUTTON, self.OnClick)
        self.Show()

    def update(self, msg):
        self.gauge.SetValue(msg.data)

    def OnClick(self, evt):
        for i in range(10):
            wx.CallAfter(pub.sendMessage, "update", i + 1)
            time.sleep(1)

if __name__ == '__main__':
    app = wx.App()
    Window()
    app.MainLoop()

【问题讨论】:

    标签: multithreading wxpython


    【解决方案1】:

    这是因为使用了“CallAfter”。如果以这种方式调用“sendMessage”,实际上是在事件处理程序结束后调用。

    你可以这样试试:

    for i in range(10):
        pub.sendMessage("update", i+1)
        time.sleep(1)
    

    编辑:

    将此“sendMessage”从事件处理程序中取出。

        import time
        import wx
        from wx.lib.pubsub import Publisher as pub
    
        class Window(wx.Frame):
            def __init__(self):
                wx.Frame.__init__(self, None, title="wxGauge")
                self.sizer = wx.BoxSizer(wx.VERTICAL)
                self.gauge = wx.Gauge(self, range=10)
                self.btn = wx.Button(self, label="Start process")
                self.sizer.Add(self.gauge)
                self.sizer.Add(self.btn)
                self.SetSizerAndFit(self.sizer)
                pub.subscribe(self.update, "update")
                self.btn.Bind(wx.EVT_BUTTON, self.OnClick)
    
                self.Bind(wx.EVT_TIMER, self.TimerHandler)
                self.timer = wx.Timer(self)
                self.gaugeIndex = 0
                self.Show()
    
            def TimerHandler(self, event):
                self.gaugeIndex += 1
                pub.sendMessage("update", self.gaugeIndex)
                if self.gaugeIndex == 10:
                    self.timer.Stop()
    
            def update(self, msg):
                self.gauge.SetValue(msg.data)
    
            def OnClick(self, evt):
                self.timer.Start(1000)
    
    
        if __name__ == '__main__':
            app = wx.App(redirect=False)
            Window()
            app.MainLoop()
    

    【讨论】:

    • 这也不起作用,GUI 冻结了 10 秒,然后仪表被填满。
    • 也许 sleep 冻结事件处理程序然后冻结 gui,虽然它适用于我的 wxpython 2.8 但我相信最好把计时器的东西放在事件处理程序之外.附上新的解决方案。