如何使用wxpython退出多线程GUI?

时间:2018-09-13 21:41:48

标签: python python-3.x multithreading user-interface wxpython

非常简单的问题。如何在run()函数完成5秒后退出该程序?

# Import Libraries
import requests, os, sys, zipfile, shutil, subprocess, wx, urllib, time
from threading import *

# Define variables
url = "Insert any Dropbox .zip file link here"
r = requests.get(url, stream = True)
myEVT_PROGRESS = wx.NewEventType() # Custom Event Type
EVT_PROGRESS = wx.PyEventBinder(myEVT_PROGRESS, 1) # bind specific events to event handlers

# Button definitions
ID_START = wx.NewId()

# Define notification event for thread completion
EVT_RESULT_ID = wx.NewId()

# Downloads new file
def Download():
    urllib.request.urlretrieve(url, 'File.zip')

# Extracts new file
def Extract():
    zip_ref = zipfile.ZipFile("File.zip", 'r')
    zip_ref.extractall("Folder")
    zip_ref.close()

# Deletes the .zip file but leave the folder
def Clean():
    os.remove("File.zip")

class ProgressEvent(wx.PyCommandEvent):
    """Event to signal that a status or progress changed"""
    def __init__(self, etype, eid, status=None, progress=None):
        """Creates the event object"""
        wx.PyCommandEvent.__init__(self, etype, eid)
        self._status = status       # field to update label
        self._progress = progress   # field to update progress bar

    def GetValue(self):
        """Returns the value from the event.
        @return: the tuple of status and progress
        """
        return (self._status, self._progress)

# Thread class that executes processing
class WorkerThread(Thread):
    """Worker Thread Class."""
    def __init__(self, notify_window):
        """Init Worker Thread Class."""
        Thread.__init__(self)
        self._notify_window = notify_window
        self.setDaemon(1)
        # This starts the thread running on creation.
        self.start()

    # This is what runs on a separate thread when you click the download button
    def run(self):
        # This is the code executing in the new thread.
        self.sendEvent('Checking for old files...', 00)
        self.sendEvent('Checking for old files...', 100)
        time.sleep(.5)
        if os.path.exists("Folder"):
            self.sendEvent('Removing old files...', 200)
            subprocess.check_call(('attrib -R ' + 'Folder' + '\\* /S').split())
            shutil.rmtree('Folder')
            time.sleep(.3)
            self.sendEvent('Removed old files!', 300)
        else:
            time.sleep(.3)
            self.sendEvent('No old files found.', 300)
            time.sleep(.3)
            pass
        self.sendEvent('Downloading Package...', 400)
        Download()
        self.sendEvent('Downloading complete!', 600)
        time.sleep(.3)
        self.sendEvent('Extracting...', 650)
        Extract()
        self.sendEvent('Extraction complete!', 900)
        time.sleep(.3)
        self.sendEvent('Cleaning up...', 950)
        Clean()
        time.sleep(.3)
        self.sendEvent('Cleaning complete!', 1000)
        time.sleep(.3)
        self.sendEvent('Done!',
                       1000)
        time.sleep(5)

######### QUIT PROGRAM HERE #########

    def sendEvent(self, status=None, progress=None):
        # Send event to main frame, first param (str) is for label, second (int) for the progress bar
        evt = ProgressEvent(myEVT_PROGRESS, -1, status, progress)
        wx.PostEvent(self._notify_window, evt)

# GUI Frame class that spins off the worker thread
class MainFrame(wx.Frame):
    """Class MainFrame."""    
    def __init__(self, parent, id):
        """Create the MainFrame."""
        wx.Frame.__init__(self, parent, id, 'RFMP GUInstaller', 
                          style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER
                          ^ wx.MAXIMIZE_BOX)
        self.SetSize(400, 350)
        wx.Button(self, ID_START, 'Download', size=(300,50), pos=(42,250))
        self.Bind(wx.EVT_BUTTON, self.OnStart, id=ID_START)
        self.status = wx.StaticText(self, -1, '', pos=(7,200), style=wx.NO_BORDER)
        self.status.SetBackgroundColour((255,255,0)) # set text back color
        self.gauge = wx.Gauge(self, range = 1000, size = (370, 30), pos=(7,217),
                              style =  wx.GA_HORIZONTAL)

        # And indicate we don't have a worker thread yet
        self.worker = None
        self.Bind(EVT_PROGRESS, self.OnResult) # Bind the custom event to a function

    def OnStart(self, event):
        # Trigger the worker thread unless it's already busy
        if not self.worker:
            self.status.SetLabel('')
            self.worker = WorkerThread(self)

    def OnResult(self, event):
        """Our handler for our custom progress event."""
        status, progress = event.GetValue()
        self.status.SetLabel(status)
        if progress:
            self.gauge.SetValue(progress)

class MainApp(wx.App):
    """Class Main App."""
    def OnInit(self):
        """Init Main App."""
        self.frame = MainFrame(None, -1)
        self.frame.Show(True)
        self.SetTopWindow(self.frame)
        return True

# Main Loop
if __name__ == '__main__':
    app = MainApp(0)
    app.MainLoop()

显然,我需要添加更多详细信息,因为程序中包含大量代码,因此在这里我用了一个不必要的长句子,使我的帖子看起来更具描述性,因为它需要堆栈溢出网站的要求我的代码更具描述性,或者因为我昨天才开始编写GUI python,所以我无法发布需要帮助修复的非常长的代码。

2 个答案:

答案 0 :(得分:1)

在您的<xsl:template match="name//text()[not(parent::xsample)]"> 函数中,只需发送状态为“ Terminate”且进度值为-1的信号。

Run

您的self.sendEvent('Terminate...', -1) 函数,然后变成这样:

OnResult

答案 1 :(得分:0)

在run()中,您可以添加:

import time
import sys
start = time.time()
PERIOD_OF_TIME = 5    # 5 seconds
...
your code
...
if time.time() > start + PERIOD_OF_TIME:
    sys.exit(0)    # 5 seconds up, quit program
相关问题