wxPython - 如何在另一个进程发生时显示加载栏?

时间:2013-09-02 19:51:54

标签: python wxpython

我正在wxPython中创建一个RSS feed聚合器客户端,我正在尝试实现的一个函数是刷新函数,它刷新feed并显示任何新文章。但是,每次调用刷新功能时,必须再次刮取所有Web文章并在屏幕上显示,这通常需要大约6-7秒。因此我创建了一个wx.Dialog类,其载荷计持续7秒。我的目的是在所有文章被刮掉时用显示器显示这个对话框。我尝试使用线程模块执行此操作,但无济于事。弹出对话框但是测量仪在所有事情都已发生之前不会开始。这是当前的代码:

def OnRefresh(self, e): #Reloads the scraper module and mimics previous processes, replaces the old articles in the list with the new articles
    gauge = LoadingGauge(None, title='', size=(300,200))
    threading.Thread(target=gauge.InitUI()).start() #Show the loading screen while the main program is refreshing (But it doesn't...)
    reload(scraper)
    self.webpage = scraper.Scraper('http://feeds.huffingtonpost.com/huffingtonpost/LatestNews')
    self.statusBar.SetStatusText('Refreshing feed...')
    self.webpage.scrape()
    self.statusBar.SetStatusText('')
    self.listCtrl.DeleteAllItems()
    for i in range(0, 15):
        self.listCtrl.InsertStringItem(i, self.webpage.titles[i])
    self.browser.LoadURL(self.webpage.links[0])
    self.Layout()

如果有人能够抓住我的错误或将我重定向到一个新的解决方案,那就太好了。 可在此处找到完整代码:https://github.com/JackSac67/Huffeeder,可在此处找到用于刷新工具的图标:http://files.softicons.com/download/internet-cons/feedicons-2-icons-by-zeusbox-studio/png/32/reload.png

1 个答案:

答案 0 :(得分:3)

您需要将正在执行抓取的线程中的消息发送到主应用程序,以告知它更新进度条。这意味着你必须使用wxPython线程安全方法之一:

  • wx.CallAfter
  • wx.CallLater
  • wx.PostEvent

我认为最简单的方法之一就是将pubsub与CallAfter结合使用。您可以使用pubsub将消息发布到对话框,该对话框中需要有一个侦听器。您可以在此处了解如何执行此操作:http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/

更新:

这是一个示例应用程序,它显示了如何定期从线程更新仪表小部件(与wxPython 2.8一起使用):

import time
import wx

from threading import Thread

from wx.lib.pubsub import Publisher

########################################################################
class TestThread(Thread):
    """Test Worker Thread Class."""

    #----------------------------------------------------------------------
    def __init__(self):
        """Init Worker Thread Class."""
        Thread.__init__(self)
        self.start()    # start the thread

    #----------------------------------------------------------------------
    def run(self):
        """Run Worker Thread."""
        # This is the code executing in the new thread.
        for i in range(20):
            time.sleep(1)
            wx.CallAfter(Publisher().sendMessage, "update", "")

########################################################################
class MyProgressDialog(wx.Dialog):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Dialog.__init__(self, None, title="Progress")
        self.count = 0

        self.progress = wx.Gauge(self, range=20)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.progress, 0, wx.EXPAND)
        self.SetSizer(sizer)

        # create a pubsub receiver
        Publisher().subscribe(self.updateProgress, "update")

    #----------------------------------------------------------------------
    def updateProgress(self, msg):
        """"""
        self.count += 1

        if self.count >= 20:
            self.Destroy()

        self.progress.SetValue(self.count)


########################################################################
class MyForm(wx.Frame):

    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")

        # Add a panel so it looks the correct on all platforms
        panel = wx.Panel(self, wx.ID_ANY)
        self.btn = btn = wx.Button(panel, label="Start Thread")
        btn.Bind(wx.EVT_BUTTON, self.onButton)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
        panel.SetSizer(sizer)

    #----------------------------------------------------------------------
    def onButton(self, event):
        """
        Runs the thread
        """
        btn = event.GetEventObject()
        btn.Disable()

        TestThread()
        dlg = MyProgressDialog()
        dlg.ShowModal()

        btn.Enable()


#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyForm().Show()
    app.MainLoop()

如果您使用的是wxPython 2.9,则pubsub已更新为使用新的pubsub API。这是一个适用于wxPython 2.9的示例:

import time
import wx

from threading import Thread

from wx.lib.pubsub import pub

########################################################################
class TestThread(Thread):
    """Test Worker Thread Class."""

    #----------------------------------------------------------------------
    def __init__(self):
        """Init Worker Thread Class."""
        Thread.__init__(self)
        self.start()    # start the thread

    #----------------------------------------------------------------------
    def run(self):
        """Run Worker Thread."""
        # This is the code executing in the new thread.
        for i in range(20):
            time.sleep(1)
            wx.CallAfter(pub.sendMessage, "update", msg="")

########################################################################
class MyProgressDialog(wx.Dialog):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Dialog.__init__(self, None, title="Progress")
        self.count = 0

        self.progress = wx.Gauge(self, range=20)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.progress, 0, wx.EXPAND)
        self.SetSizer(sizer)

        # create a pubsub receiver
        pub.subscribe(self.updateProgress, "update")

    #----------------------------------------------------------------------
    def updateProgress(self, msg):
        """"""
        self.count += 1

        if self.count >= 20:
            self.Destroy()

        self.progress.SetValue(self.count)


########################################################################
class MyForm(wx.Frame):

    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")

        # Add a panel so it looks the correct on all platforms
        panel = wx.Panel(self, wx.ID_ANY)
        self.btn = btn = wx.Button(panel, label="Start Thread")
        btn.Bind(wx.EVT_BUTTON, self.onButton)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
        panel.SetSizer(sizer)

    #----------------------------------------------------------------------
    def onButton(self, event):
        """
        Runs the thread
        """
        btn = event.GetEventObject()
        btn.Disable()

        TestThread()
        dlg = MyProgressDialog()
        dlg.ShowModal()

        btn.Enable()


#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyForm().Show()
    app.MainLoop()