Как выйти из многопоточного графического интерфейса с wxpython? - PullRequest
0 голосов
/ 14 сентября 2018

Очень простой вопрос.Как заставить эту программу завершить работу через 5 секунд после завершения функции 'run ()'?

# 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 голосов
/ 14 сентября 2018

В вашей функции Run просто отправьте сигнал со статусом «Завершение» и значением прогресса, например, -1.

self.sendEvent('Terminate...', -1)

Ваша функция OnResult затем становится примерно такой:

def OnResult(self, event):
    """Our handler for our custom progress event."""
    status, progress = event.GetValue()
    self.status.SetLabel(status)
    if progress >= 0:
        self.gauge.SetValue(progress)
    else:
        # The worker is done
        self.worker = None
        time.sleep(5)
        self.Close()
        self.Destroy()
0 голосов
/ 14 сентября 2018

В 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
...