如何在框架关闭时终止或杀死python GUI应用程序中的子线程

Posted

技术标签:

【中文标题】如何在框架关闭时终止或杀死python GUI应用程序中的子线程【英文标题】:how to terminate or kill child thread in python GUI application on frame close 【发布时间】:2015-11-26 19:08:31 【问题描述】:

我使用 wx.Python 编写了一个 python 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

【问题讨论】:

您使用什么操作系统?如果它的窗口,在 Python 中没有办法真正杀死一个线程,只有进程可以被“杀死”。如果是 Linux,情况就不同了——这里的线程可以被杀死。 我正在使用 Windows。你能告诉我如何改变我的代码来处理流程吗? 【参考方案1】:

当您使用 Windows 时,Python 无法在线程未终止时实际“杀死”线程。如何解决这个问题有很多可能性。 例如:

与线程通信并告诉它停止 将“worker”作为外部进程运行(例如使用 popen) 使用 multiprocessing.Process

这是最后一个示例。请注意,您需要使用 multiprocessing.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()

【讨论】:

以上是关于如何在框架关闭时终止或杀死python GUI应用程序中的子线程的主要内容,如果未能解决你的问题,请参考以下文章

应用程序被杀死/关闭/未打开时的 IOS 推送通知操作

Qt Dialog窗口关闭时如何终止QEventLoop

即使应用程序处于终止状态或被杀死,如何在 iOS 中获取位置更新? [复制]

将用户位置发送到服务器(Web文件)甚至应用程序已关闭或终止或终止iOS Swift

Gunicorn - 如果客户端关闭他们的连接,如何杀死工人?

当应用程序在颤动中被杀死/终止时,从后台事件启动应用程序