【问题标题】:My python installer freezes while working. How do I fix it?我的 python 安装程序在工作时冻结。我如何解决它?
【发布时间】:2018-09-12 22:26:23
【问题描述】:

我用 wxPython 为游戏制作了一个非常简单的 GUI 安装程序。虽然它适用于游戏,但如果您有链接,它在技术上可用于下载和提取任何 zip 文件。问题是当我运行程序时 GUI 冻结。它仍然像它应该的那样下载和提取,但是在发生这种情况时 GUI 完全冻结。除非我可以解冻它,否则我无法更新文本框或制作下载栏。我知道它为什么会冻结我只是不知道如何解决它。有人可以帮帮我吗?

这是我的代码:

import requests, os, sys, zipfile, shutil, subprocess, wx, urllib

url = "{Put any zip file URL here to test the program}"
r = requests.get(url, stream = True)

class Frame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
        myPanel = wx.Panel(self,-1)
        myButton = wx.Button(myPanel, -1, 'Download', size=(300,50), pos=(40,350))
        myButton.Bind(wx.EVT_LEFT_DOWN, self.onClick)
        self.Show(True)
    def onClick(self, e):
        print ('Clicked')
        if os.path.exists("RFMB6_WINDOWS"):
            print('\n\nRemoving old RFMP files...')
            subprocess.check_call(('attrib -R ' + 'RFMB6_WINDOWS' + '\\* /S').split())
            shutil.rmtree('RFMB6_WINDOWS')
            print('\nRemoved old files.')
        else:
            pass

        print('\n\nDownloading:')
        urllib.request.urlretrieve(url, 'RFMP.zip')
        print('\nDownload Complete.')
        print('\n\nExtracting...')
        zip_ref = zipfile.ZipFile("RFMP.zip", 'r')
        zip_ref.extractall("RFMB6_WINDOWS")
        zip_ref.close()
        print('\nExtraction Complete')
        print('\n\nCleaning up...')
        os.remove("RFMP.zip")
        print('\nDone! You have succesfully installed the newest version of the Ravenfield Multiplayer Private Alpha.')

app = wx.App()
frame = Frame(None, wx.ID_ANY, 'Image')
app.MainLoop()

【问题讨论】:

  • 下载 zip 文件需要多长时间?它可能会冻结,因为它仍在下载文件。如果让它运行会发生什么?
  • 该程序运行良好,但下载时冻结并显示“无响应”。我需要一些方法来多线程它我只是不知道如何。就像我说的,我知道它为什么会冻结,我只需要知道如何解决它。

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


【解决方案1】:

好的,所以我想通了。正如我所说,我需要对 GUI 进行多线程处理,但当时我无法弄清楚。我现在有。我需要做的是多线程 GUI 和我的“进程”在不同的线程上。这意味着 GUI(您所看到的)运行在与处理数据(下载、提取等)的线程不同的线程上。

在您使用此代码之前,我想让您知道这不是一个完成的程序。这只是从下载链接下载和提取 .zip 而不会冻结的最低要求。

这是我现在用来解决问题的代码:

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

# Define variables
url = "Put any zip file URL here to test the program"
r = requests.get(url, stream = True)

# Button definitions
ID_START = wx.NewId()

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

# Check  for old files
def Check():
    if os.path.exists("Folder"):
        print('\n\nRemoving old files...')
        subprocess.check_call(('attrib -R ' + 'Folder' + '\\* /S').split())
        shutil.rmtree('Folder')
        print('\nRemoved old files.')
    else:
        pass

# Download new file
def Download():
    print('\n\nDownloading:')
    urllib.request.urlretrieve(url, 'temp.zip')
    print('\nDownload Complete.')

# Extract new file
def Extract():
    print('\n\nExtracting...')
    zip_ref = zipfile.ZipFile("temp.zip", 'r')
    zip_ref.extractall("Folder")
    zip_ref.close()
    print('\nExtraction Complete')

# Delete the .zip file but leave the folder
def Clean():
    print('\n\nCleaning up...')
    os.remove("temp.zip")
    print('\nDone!')

# 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
        # 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):
        """Run Worker Thread."""
        # This is the code executing in the new thread. 
        Check()
        Download()
        Extract()
        Clean()

# 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, 'GUInstaller', 
                          style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
        self.SetSize(400, 350)
        wx.Button(self, ID_START, 'Download', size=(300,50), pos=(42,250))
        self.status = wx.StaticText(self, -1, '', pos=(0,200))
        self.Bind(wx.EVT_BUTTON, self.OnStart, id=ID_START)

        # And indicate we don't have a worker thread yet
        self.worker = None

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

    def OnResult(self, event):
        """Show Result status."""
        self.status.SetLabel('Done!')
        # The worker is done
        self.worker = None

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()

附:并非所有这些都是我的代码。我从另一个网站上举了一个例子,并根据我的需要对其进行了修改。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-13
    • 1970-01-01
    • 1970-01-01
    • 2021-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多