如何在帧关闭时在python GUI应用程序中终止或终止子线程

时间:2015-09-01 13:50:46

标签: multithreading python-2.7 wxpython multiprocessing wxwidgets

我使用wx.Python编写了一个pyhton GUI应用程序 在下面的代码中,它在主框架中单击开始按钮时会做什么,它将在单独的线程中启动一个框架(MyForm),在那里它打印一些文本。我需要什么,关闭MyForm框架当前子线程执行应该终止或杀死和控制应该回到主线程。我在一个模块中编写的所有代码

import wx, wx.html
from threading import Thread
import wx
import control
import sys

class Frame(wx.Frame):

    def __init__(self,parent,id):
        wx.Frame.__init__(self, None, -1, 'Sample frame', size=(750, 350))
        self.panel = wx.Panel(self, -1)

        '''
        button <start> to start the script
        '''
        self.button_start = wx.Button(self.panel,-1,"Start",pos=(100,220),size=(100,40))
        self.button_close = wx.Button(self.panel,-1,"Close",pos=(300,220),size=(100,40))

        self.Bind(wx.EVT_BUTTON,self.click_start,self.button_start)
        self.Bind(wx.EVT_BUTTON, self.OnClose,self.button_close)

    def click_start (self,event):
        self.MyTask()

    def MyTask(self):
        step_a = 1
        step_b = 50

        self.frame2 = MyForm().Show()
        TestingThread(step_a, step_b)

    def OnCloseWindow(self,event):
        self.Close(True)

    def OnClose(self, event):
        dlg = wx.MessageDialog(self, 
            "Do you really want to close this application?",
            "Confirm Exit", wx.OK|wx.CANCEL|wx.ICON_QUESTION)
        result = dlg.ShowModal()
        dlg.Destroy()
        if result == wx.ID_OK:
            self.Destroy()

class App(wx.App):

    def __init__(self, redirect=True, filename=None):

        wx.App.__init__(self, redirect, filename)

    def OnInit(self):
        self.frame = Frame(parent=None, id=-1)  #Create Frame
        self.frame.Show()
        return True

    def OnExit(self):
        self.Exit()

class TestingThread(Thread):
"""Test Worker Thread Class."""

    def __init__(self,a, b):    
        """Init Worker Thread Class."""
        Thread.__init__(self)

        self.a = a
        self.b = b
        self.start() 

    def run(self):

        self.res=control.main(self.a, self.b)

class RedirectText(object):
    def __init__(self,aWxTextCtrl):
        self.out=aWxTextCtrl

    def write(self,string):
        self.out.WriteText(string)

class MyForm(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "wxPython Log Redirect Box",size= (500,300))
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        panel = wx.Panel(self, wx.ID_ANY)
        log = wx.TextCtrl(panel, wx.ID_ANY, size=(500,300),
                          style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL|wx.TE_NOHIDESEL)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(log, 1, wx.ALL|wx.EXPAND, 5)

        panel.SetSizer(sizer)

        # redirect text here
        redir=RedirectText(log)
        sys.stdout=redir

    def OnClose(self, event):

        dlg = wx.MessageDialog(self, 
            "Do you really want to close this application?",
            "Confirm Exit", wx.OK|wx.CANCEL|wx.ICON_QUESTION)
        result = dlg.ShowModal()
        dlg.Destroy()
        if result == wx.ID_OK:
            self.Destroy()
            self.MakeModal(False)  

if __name__ == '__main__':

    app = App(redirect=False)
    app.MainLoo

1 个答案:

答案 0 :(得分:0)

当您使用Windows时,Python无法实际杀死&#34; Kill&#34;一个线程没有终止。如何解决这个问题有很多可能性。 E.g:

  • 与线程通信并告诉它停止
  • 运行&#34; worker&#34;作为外部过程(例如与popen)
  • 使用multiprocessing.Process

这是最后一个例子。请注意,您需要使用多处理.Queue或IPC功能(例如Pyro4)与流程进行通信。

from multiprocessing import Process

import time
import wx


procs = []

def subproc():
    while True:
        print("Hello World")
        time.sleep(1)

def OnStart(event):
    myProc = Process(target=subproc)
    myProc.start()
    print("Started new process with PID {}".format(myProc.pid))
    procs.append(myProc)

def OnStop(event):
    for proc in procs:
        proc.terminate()


if __name__ == '__main__':
    app = wx.App()

    frame = wx.Frame(None, -1)
    frame.Show()

    sizer = wx.BoxSizer(wx.HORIZONTAL)
    btn1 = wx.Button(frame, -1, "Start")
    btn2 = wx.Button(frame, -1, "Stop")
    sizer.Add(btn1, 0)
    sizer.Add(btn2, 1)
    frame.SetSizer(sizer)
    frame.Fit()
    frame.Layout()
    frame.Bind(wx.EVT_BUTTON, OnStart, id = btn1.GetId())
    frame.Bind(wx.EVT_BUTTON, OnStop, id = btn2.GetId())
    app.MainLoop()