Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用Kivy应用程序下载文件,无需锁定事件循环_Python_Kivy - Fatal编程技术网

Python 使用Kivy应用程序下载文件,无需锁定事件循环

Python 使用Kivy应用程序下载文件,无需锁定事件循环,python,kivy,Python,Kivy,这是一个Kivy应用程序,它有一个按钮和一个进度条。按下按钮后,将从web下载一个ZIP文件并解压缩。进度条前进以标记下载进度 问题是,下载锁定了Kivy事件循环,在下载过程中冻结了应用程序。如何在后台下载和解压缩文件 from __future__ import division import os import requests import zipfile from kivy.app import App from kivy.lang import Builder from kivy.ui

这是一个Kivy应用程序,它有一个按钮和一个进度条。按下按钮后,将从web下载一个ZIP文件并解压缩。进度条前进以标记下载进度

问题是,下载锁定了Kivy事件循环,在下载过程中冻结了应用程序。如何在后台下载和解压缩文件

from __future__ import division
import os
import requests
import zipfile
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout

ZIP_URL = 'https://www.python.org/ftp/python/3.5.1/python-3.5.1-embed-win32.zip'
ZIP_FILENAME = 'Python351.zip'

kv_string = """
<RootWidget>
    BoxLayout:
        orientation: "vertical"
        Button:
            id: download_button
            text: "Download content"
            on_press: self.parent.parent.download_content()
        ProgressBar:
            id: download_progress_bar
            max: 1
            value: 0.1
"""

Builder.load_string(kv_string)


class RootWidget(BoxLayout):
    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)

    def download_content(self):
        self.ids["download_button"].disabled = True

        total_size_KiB = 6023182 / 1024 # DEBUG: hardcoded
        print("Downloading file: %s" % ZIP_URL)
        with open(ZIP_FILENAME, 'wb') as handle:
            response = requests.get(ZIP_URL, stream=True)

            if not response.ok:
                print("Something went wrong.")
                return

            current_size_KiB = 0
            for block in response.iter_content(1024):
                percent_downloaded = current_size_KiB / total_size_KiB
                if not current_size_KiB % 100:
                    print("%.2f%% downloaded so far" % (percent_downloaded * 100))
                self.ids['download_progress_bar'].value = percent_downloaded

                handle.write(block)

                current_size_KiB += 1

        self.unzip_content()

    def unzip_content(self):
        print("Unzipping file")
        fh = open(ZIP_FILENAME, 'rb')
        z = zipfile.ZipFile(fh)
        ZIP_EXTRACT_FOLDER = ZIP_FILENAME + '_extracted'
        if not os.path.exists(ZIP_EXTRACT_FOLDER):
            os.makedirs(ZIP_EXTRACT_FOLDER)
        z.extractall(ZIP_EXTRACT_FOLDER)
        fh.close()
        os.remove(ZIP_FILENAME)

        print("Done")


class MyApp(App):

    def build(self):
        return RootWidget()


if __name__ == '__main__':
    MyApp().run()
来自未来进口部的

导入操作系统
导入请求
进口拉链
从kivy.app导入应用程序
从kivy.lang导入生成器
从kivy.uix.boxlayout导入boxlayout
邮政编码https://www.python.org/ftp/python/3.5.1/python-3.5.1-embed-win32.zip'
ZIP_文件名='Python351.ZIP'
kv_字符串=”“
盒子布局:
方向:“垂直”
按钮:
id:下载按钮
文本:“下载内容”
按:self.parent.parent.download\u content()
进度条:
id:下载进度条
最高:1
数值:0.1
"""
建筑商。荷载串(千伏串)
类RootWidget(BoxLayout):
定义初始(自我,**kwargs):
超级(RootWidget,self)。\uuuuu init\uuuuuu(**kwargs)
def下载内容(自我):
self.ids[“下载按钮”].disabled=True
总大小=6023182/1024调试:硬编码
打印(“下载文件:%s”%ZIP\u URL)
以open(ZIP_文件名,'wb')作为句柄:
response=requests.get(ZIP\u URL,stream=True)
如果没有响应。确定:
打印(“出了问题。”)
返回
当前大小=0
对于响应中的块。iter_内容(1024):
下载百分比=当前大小/总大小
如果不是当前大小,请输入%100:
打印(“%.2f%%下载到目前为止”%(下载百分比*100))
self.ids['download\u progress\u bar'].value=下载百分比
handle.write(块)
当前大小\u KiB+=1
self.unzip_content()
def解压_内容(自身):
打印(“解压缩文件”)
fh=打开(ZIP_文件名'rb')
z=zipfile.zipfile(fh)
ZIP_EXTRACT_FOLDER=ZIP_FILENAME+“_EXTRACT”
如果不存在os.path(ZIP\u EXTRACT\u文件夹):
os.makedirs(ZIP\u EXTRACT\u文件夹)
z、 extractall(ZIP\u EXTRACT\u文件夹)
fh.close()
删除(ZIP_文件名)
打印(“完成”)
类别MyApp(应用程序):
def生成(自):
返回RootWidget()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
MyApp().run()

首先,正如@Nykakin所建议的,要使下载异步,请使用
kivy.network.urlrequest.urlrequest

def download_content(self):
    self.ids["download_button"].disabled = True
    req = UrlRequest(ZIP_URL, on_progress=self.update_progress,
                     chunk_size=1024, on_success=self.unzip_content,
                     file_path=ZIP_FILENAME)

def update_progress(self, request, current_size, total_size):
    self.ids['download_progress_bar'].value = current_size / total_size
其次,正如@KeyWeeUsr所建议的,通过使用
线程化
模块,更改解压方法,使其不会阻塞事件循环:

def unzip_content(self, req, result):
    threading.Thread(target=self.unzip_thread).start()

def unzip_thread(self):
    # ... (same as unzip_content method in question)
以下是全新版本:

from __future__ import division
import os
import zipfile
import threading
import time
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.network.urlrequest import UrlRequest

ZIP_URL = 'https://www.python.org/ftp/python/3.5.1/python-3.5.1-embed-win32.zip'
ZIP_FILENAME = 'Python351.zip'

kv_string = """
<RootWidget>
    BoxLayout:
        orientation: "vertical"
        Button:
            id: download_button
            text: "Download content"
            on_press: self.parent.parent.download_content()
        ProgressBar:
            id: download_progress_bar
            max: 1
            value: 0
"""

Builder.load_string(kv_string)


class RootWidget(BoxLayout):

    stop = threading.Event()    

    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)

    def download_content(self):
        self.ids["download_button"].disabled = True
        req = UrlRequest(ZIP_URL, on_progress=self.update_progress,
                         chunk_size=1024, on_success=self.unzip_content,
                         file_path=ZIP_FILENAME)

    def update_progress(self, request, current_size, total_size):
        self.ids['download_progress_bar'].value = current_size / total_size

    def unzip_content(self, req, result):
        threading.Thread(target=self.unzip_thread).start()

    def unzip_thread(self):
        print("Unzipping file")
        fh = open(ZIP_FILENAME, 'rb')
        z = zipfile.ZipFile(fh)
        ZIP_EXTRACT_FOLDER = ZIP_FILENAME + '_extracted'
        if not os.path.exists(ZIP_EXTRACT_FOLDER):
            os.makedirs(ZIP_EXTRACT_FOLDER)
        z.extractall(ZIP_EXTRACT_FOLDER)
        fh.close()
        os.remove(ZIP_FILENAME)
        time.sleep(4) # DEBUG: stretch out the unzip method to test threading

        print("Done")


class MyApp(App):

    def on_stop(self):
        # The Kivy event loop is about to stop, set a stop signal;
        # otherwise the app window will close, but the Python process will
        # keep running until all secondary threads exit.
        self.root.stop.set()        

    def build(self):
        return RootWidget()


if __name__ == '__main__':
    MyApp().run()
来自未来进口部的

导入操作系统
进口拉链
导入线程
导入时间
从kivy.app导入应用程序
从kivy.lang导入生成器
从kivy.uix.boxlayout导入boxlayout
从kivy.network.urlrequest导入urlrequest
邮政编码https://www.python.org/ftp/python/3.5.1/python-3.5.1-embed-win32.zip'
ZIP_文件名='Python351.ZIP'
kv_字符串=”“
盒子布局:
方向:“垂直”
按钮:
id:下载按钮
文本:“下载内容”
按:self.parent.parent.download\u content()
进度条:
id:下载进度条
最高:1
数值:0
"""
建筑商。荷载串(千伏串)
类RootWidget(BoxLayout):
stop=threading.Event()
定义初始(自我,**kwargs):
超级(RootWidget,self)。\uuuuu init\uuuuuu(**kwargs)
def下载内容(自我):
self.ids[“下载按钮”].disabled=True
req=UrlRequest(ZIP\u URL,on\u progress=self.update\u progress,
chunk\u size=1024,on\u success=self.unzip\u content,
文件路径=ZIP文件名)
def更新进度(自身、请求、当前大小、总大小):
self.ids['download\u progress\u bar'].value=当前大小/总大小
def解压_内容(自身、请求、结果):
threading.Thread(target=self.unzip_Thread).start()
def解压_线程(自):
打印(“解压缩文件”)
fh=打开(ZIP_文件名'rb')
z=zipfile.zipfile(fh)
ZIP_EXTRACT_FOLDER=ZIP_FILENAME+“_EXTRACT”
如果不存在os.path(ZIP\u EXTRACT\u文件夹):
os.makedirs(ZIP\u EXTRACT\u文件夹)
z、 extractall(ZIP\u EXTRACT\u文件夹)
fh.close()
删除(ZIP_文件名)
time.sleep(4)#DEBUG:扩展解压方法以测试线程
打印(“完成”)
类别MyApp(应用程序):
def on_停止(自):
#Kivy事件循环即将停止,设置停止信号;
#否则,应用程序窗口将关闭,但Python进程将关闭
#继续运行,直到所有次线程退出。
self.root.stop.set()
def生成(自):
返回RootWidget()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
MyApp().run()
+您可以使用,以便在web上发出异步请求。您还可以在“进度”属性中将回调设置为
,以更新进度条。