1

我正在 wxPython 中创建一个 RSS 提要聚合器客户端,我尝试实现的一个功能是刷新提要并显示任何新文章的刷新功能。但是每次调用刷新函数时,都必须重新抓取所有网页文章并显示在屏幕上,这通常需要 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

4

1 回答 1

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()
于 2013-09-03T13:38:32.727 回答