1

wxPython で RSS フィード アグリゲーター クライアントを作成しています。実装しようとしている機能の 1 つは、フィードを更新して新しい記事を表示する更新機能です。ただし、更新機能が呼び出されるたびに、すべての Web 記事を再度スクレイピングして画面に表示する必要があります。これには通常 6 ~ 7 秒かかります。したがって、7 秒間持続する負荷ゲージを備えた wx.Dialog クラスを作成しました。私の意図は、すべての記事がスクレイピングされている間、ゲージでこのダイアログを表示することです。threading モジュールでこれを実行しようとしましたが、役に立ちませんでした。ダイアログが表示されますが、すべてが完了するまでゲージは開始されません。現在のコードは次のとおりです。

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

これを行う最も簡単な方法の 1 つは、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 に答える