2017-08-15 114 views
0

我很新的wxPython的,也並不熟悉線程的概念。如果有人能爲我的問題提供信息資源或建議,我將非常感激。如何使用wx.CallAfter()返回的條件終止線程?

我創造了使用wxPython的,允許用戶輸入的運行我的腳本的GUI。由於一步需要20分鐘才能運行,因此我打算創建一個進度對話框來顯示用戶進度並允許他們中止進度。我已經使用下面的示例代碼對此進行了測試。

但是,我不能停止WorkThread即使我點擊了進度對話框的停止按鈕。我如果使用返回值從pb.sendMessage聲明試圖 1.化妝() 2.創建ProgressDialog對象WorkThread啓動時,並呼籲ProgressDialog.abort 但他們沒有工作。我想知道是否有概念性錯誤實現這樣的代碼來實現我想要做的事情?或者如果這可以糾正?任何提示將不勝感激!

class WorkThread(Thread): 

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

    def run(self): 

     for i in range(10): 
      time.sleep(1) 
      val = 100/10 
      wx.CallAfter(pub.sendMessage, "update", step=val) 
     print 'Finish Run' 

class ProgressDialog(wx.Dialog): 
    def __init__(self): 

     wx.Dialog.__init__(self, None) 
     self.abort = False 
     self.progress = 0 

     bSizer2 = wx.BoxSizer(wx.VERTICAL) 
     self.gauge = wx.Gauge(self, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.GA_HORIZONTAL) 
     self.gauge.SetValue(0) 

     self.m_button1 = wx.Button(self, wx.ID_ANY, u"Stop Training", wx.DefaultPosition, wx.DefaultSize, 0) 
     bSizer2.Add(self.gauge, 0, 0, 5) 
     bSizer2.Add(self.m_button1, 0, 0, 5) 

     self.SetSizer(bSizer2) 
     self.Layout() 
     self.Centre(wx.BOTH) 

     ## Connect Events 

     self.m_button1.Bind(wx.EVT_BUTTON, self.on_cancel) 
     pub.subscribe(self.updateProgress, "update") 

    def updateProgress(self, step): 
     self.progress += step 

     if self.abort: 
      self.Update() 
      self.Close() 
     elif self.progress >= 100: 
      self.gauge.SetValue(self.progress) 
      self.Update() 
      self.Close() 
     else: 
      self.gauge.SetValue(self.progress) 

    def on_cancel(self, event): 
     """Cancels the conversion process""" 
     self.abort = True 
     print 'Click' 
     # pub.unsubscribe(self.if_abort, 'cancel') 

    def __del__(self): 
     pass 


######################################################################################## 

class MainFrame(wx.Frame): 
    # ---------------------------------------------------------------------- 
    def __init__(self,parent): 
     wx.Frame.__init__(self,parent) 
     # 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): 
     btn = event.GetEventObject() 
     btn.Disable() 
     WorkThread() 
     self.dlg = ProgressDialog() 
     self.dlg.ShowModal() 
     btn.Enable() 

app = wx.App() 
frame = MainFrame(None) 
frame.Show(True) 
# start the applications 
app.MainLoop() 

回答

0

您需要線程內的方法來阻止它。
你也應該等它停下來。
下面是一個選項使用代碼:

from threading import Thread 
import wx 
from wx.lib.pubsub import pub 
import time 
class WorkThread(Thread): 

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

    def run(self): 
     for i in range(10): 
      if self.stop_work_thread == 1: 
       break 
      time.sleep(1) 
      val = 100/10 
      wx.CallAfter(pub.sendMessage, "update", step=val) 
     wx.CallAfter(pub.sendMessage, "finish") 
     return 

    def stop(self): 
     self.stop_work_thread = 1 

class ProgressDialog(wx.Dialog): 
    def __init__(self,parent): 
     wx.Dialog.__init__(self, parent) 
     self.parent = parent 
     self.abort = False 
     self.progress = 0 

     bSizer2 = wx.BoxSizer(wx.VERTICAL) 
     self.gauge = wx.Gauge(self, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.GA_HORIZONTAL) 
     self.gauge.SetValue(0) 

     self.m_button1 = wx.Button(self, wx.ID_ANY, u"Stop Training", wx.DefaultPosition, wx.DefaultSize, 0) 
     bSizer2.Add(self.gauge, 0, 0, 5) 
     bSizer2.Add(self.m_button1, 0, 0, 5) 

     self.SetSizer(bSizer2) 
     self.Layout() 
     self.Centre(wx.BOTH) 

     ## Connect Events 

     self.m_button1.Bind(wx.EVT_BUTTON, self.on_cancel) 
     pub.subscribe(self.updateProgress, "update") 
     pub.subscribe(self.on_finish, "finish") 

    def updateProgress(self, step): 
     self.progress += step 
     self.gauge.SetValue(self.progress) 

    def on_cancel(self, event): 
     """Cancels the conversion process""" 
     self.parent.work.stop() 
     self.parent.work.join() 
     pub.unsubscribe(self.updateProgress, "update") 
     pub.unsubscribe(self.on_finish, "finish") 
     self.Destroy() 
     # pub.unsubscribe(self.if_abort, 'cancel') 

    def on_finish(self): 
     """conversion process finished""" 
     pub.unsubscribe(self.updateProgress, "update") 
     pub.unsubscribe(self.on_finish, "finish") 
     self.Close() 

    def __del__(self): 
     pass 


######################################################################################## 

class MainFrame(wx.Frame): 
    # ---------------------------------------------------------------------- 
    def __init__(self,parent): 
     wx.Frame.__init__(self,parent) 
     # Add a panel so it looks the correct on all platforms 
     self.panel = wx.Panel(self, wx.ID_ANY) 
     self.btn = btn = wx.Button(self.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) 
     self.panel.SetSizer(sizer) 

    # ---------------------------------------------------------------------- 
    def onButton(self, event): 
     btn = event.GetEventObject() 
     btn.Disable() 
     self.panel.work = WorkThread() 
     self.dlg = ProgressDialog(self.panel) 
     self.dlg.ShowModal() 
     btn.Enable() 

app = wx.App() 
frame = MainFrame(None) 
frame.Show(True) 
# start the applications 
app.MainLoop() 
+0

太謝謝你了!它完美的工作!我嘗試使用與self.stop_work_thread類似的標誌來停止WorkThread中的for-loop,但當時並不奏效。是否因爲我沒有使用MainFrame作爲ProgressDialog的父項,所以它根本沒有鏈接? – paraeve

+0

可能,但它看起來並不像有辦法阻止線程本身,只是進度條。 'on_cancel'例程現在停止線程並等待它完成('.join'語句)。 –

+0

謝謝你的詳細回覆! – paraeve