我正在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
答案 0 :(得分:3)
您需要将正在执行抓取的线程中的消息发送到主应用程序,以告知它更新进度条。这意味着你必须使用wxPython线程安全方法之一:
我认为最简单的方法之一就是将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()