简体   繁体   中英

wx.Python killing children thread

I have a GUI application, running in my main thread, and some children thread doing stuff in the background. I binded the close button to a method, to do stuff before closing the software, but I can't figure out how to stop the children threads

self.Bind(wx.EVT_CLOSE, self.onCloseFrame)

def onCloseFrame(self, event):
    do_stuff()
    # stop threads here
    self.Destroy()

Is there a way to do that?

This is a test I mocked up for something.
It's a bit more complicated than it needs to be, because I wanted multiple progress indicators but you should be able to get the gist of it.

Include a termination function and trigger it, if you wish to end the thread before it has naturally finished.
In this instance, the thread times out after a minute but it could be doing whatever.

Click Start for as many threads as you wish to have running simultaneously.

import time
import wx
from threading import Thread
import wx.lib.newevent
progress_event, EVT_PROGRESS_EVENT = wx.lib.newevent.NewEvent()

class ProcessingFrame(wx.Frame):

    def __init__(self, title, parent=None):
        wx.Frame.__init__(self, parent=parent, title=title)
        panel = wx.Panel(self)
        self.parent = parent
        self.btn = wx.Button(panel,label='Stop processing', size=(200,30), pos=(10,10))
        self.btn.Bind(wx.EVT_BUTTON, self.OnExit)
        self.progress = wx.Gauge(panel,size=(240,10), pos=(10,50), range=60)
        self.process = wx.TextCtrl(panel,size = (200,250), pos=(10,100), style = wx.TE_MULTILINE)
        #Bind to the progress event issued by the thread
        self.Bind(EVT_PROGRESS_EVENT, self.OnProgress)
        #Bind to Exit on frame close
        self.Bind(wx.EVT_CLOSE, self.OnExit)
        self.Show()

        self.mythread = TestThread(self)

    def OnProgress(self, event):
        self.progress.SetValue(event.count)
        self.process.write("Checking process: "+event.process+"\n")
        self.Refresh()
        if event.count >= 60:
            self.OnExit(None)

    def OnExit(self, event):
        if self.mythread.isAlive():
            self.mythread.terminate() # Shutdown the thread
            self.mythread.join() # Wait for it to finish
        self.Destroy()

class TestThread(Thread):
    def __init__(self,parent_target):
        Thread.__init__(self)
        self.parent = parent_target
        self.stopthread = False
        self.time = time.time()
        self.process = 1 # Testing only - mock process id
        self.start()    # start the thread

    def run(self):
        # A loop that will run for a while then terminate
        while self.stopthread == False:
            curr_loop = int(time.time() - self.time)
            self.process += 10 # Testing only - mock process id
            if curr_loop <= 60: # Update progress bar
                time.sleep(0.1)
                evt = progress_event(count=curr_loop,process=str(self.process))
                #Send back current count for the progress bar
                try:
                    wx.PostEvent(self.parent, evt)
                except: # The parent frame has probably been destroyed
                    self.terminate()

    def terminate(self):
        self.stopthread = True

class MyPanel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.text_count = 0
        self.parent=parent
        btn_start = wx.Button(self, wx.ID_ANY, label='Start Long running process', size=(180,30), pos=(10,10))
        btn_test = wx.Button(self, wx.ID_ANY, label='Is the GUI still active?', size=(180,30), pos=(10,50))
        self.txt = wx.TextCtrl(self, wx.ID_ANY, style= wx.TE_MULTILINE, pos=(10,90),size=(400,100))
        btn_end = wx.Button(self, wx.ID_ANY, label='Stop All', size=(100,30), pos=(10,200))

        btn_start.Bind(wx.EVT_BUTTON, self.Start_Process)
        btn_test.Bind(wx.EVT_BUTTON, self.ActiveText)
        btn_end.Bind(wx.EVT_BUTTON, self.End_AllProcesses)

        self.activeframes = [] # 1 per live process

    def Start_Process(self, event):
        #thread_count = active_count()
        thread_count = len(self.activeframes) + 1
        self.activeframes.append(ProcessingFrame(title='Threaded Task '+str(thread_count), parent=self))

    def End_AllProcesses(self, event):
        while len(self.activeframes) > 0:
            try:
                self.activeframes[-1].OnExit(None)
                self.activeframes.pop(-1)
            except: # process may have finished or been stopped individually
                self.activeframes.pop(-1)

    def ActiveText(self,event):
        self.text_count += 1
        txt = "Gui is still active " + str(self.text_count)+"\n"
        self.txt.write(txt)

class MainFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, title='Main Frame', size=(600,400))
        panel = MyPanel(self)
        self.Show()


if __name__ == '__main__':
    app = wx.App(False)
    frame = MainFrame()
    app.MainLoop()

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM