使用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.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()
迈克尔·柯里

首先,按照@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的建议,通过使用以下threading模块,更改解压缩方法,以使其不会阻塞事件循环

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用scala-ssh下载文件后,应用程序不会退出

来自分类Dev

从 URL 下载文件的应用程序

来自分类Dev

AngularJS应用程序未下载文件

来自分类Dev

我的应用程序中的可下载文件

来自分类Dev

Chrome的应用程序缓存不会更新文件,即使它显示:应用程序缓存下载事件

来自分类Dev

如何在多页面应用程序中使用plotly-dash下载文件?

来自分类Dev

将图像从文件系统下载到kivy应用程序

来自分类Dev

在Electron应用程序中捕获文件下载事件

来自分类Dev

如果应用程序被服务破坏,我如何保持下载文件运行(下载)?

来自分类Dev

从闪亮的应用程序下载文件时如何设置您选择的文件名

来自分类Dev

While循环锁定应用程序

来自分类Dev

如何使用循环函数更新 python Kivy 应用程序

来自分类Dev

更改时部署ASP.Net MVC,Angular应用程序下载文件

来自分类Dev

从服务器下载文件时应用程序冻结

来自分类Dev

如何从OS X应用程序中的URL下载文件

来自分类Dev

应用程序从后台终止后是否可以继续下载文件

来自分类Dev

从Blazor客户端应用程序从ASP.NET Core API下载文件

来自分类Dev

下载文件后Blazor服务器端应用程序死亡

来自分类Dev

从服务器下载文件的GraphQL / Apollo应用程序

来自分类Dev

从请求中发送到django应用程序的url下载文件

来自分类Dev

应用程序从后台终止后是否可以继续下载文件

来自分类Dev

从命令行应用程序更改下载文件夹目标

来自分类Dev

写入沙盒应用程序中的下载文件夹

来自分类Dev

使用curl下载文件的C程序

来自分类Dev

单击“下载”链接,使用JQuery不会下载文件

来自分类Dev

Firefox下载种子使我没有打开它们的应用程序-只需打开下载文件夹

来自分类Dev

Firefox下载种子使我没有打开它们的应用程序-只需打开下载文件夹

来自分类Dev

tar文件并使用flask应用程序下载

来自分类Dev

tar文件并使用flask应用程序下载

Related 相关文章

  1. 1

    使用scala-ssh下载文件后,应用程序不会退出

  2. 2

    从 URL 下载文件的应用程序

  3. 3

    AngularJS应用程序未下载文件

  4. 4

    我的应用程序中的可下载文件

  5. 5

    Chrome的应用程序缓存不会更新文件,即使它显示:应用程序缓存下载事件

  6. 6

    如何在多页面应用程序中使用plotly-dash下载文件?

  7. 7

    将图像从文件系统下载到kivy应用程序

  8. 8

    在Electron应用程序中捕获文件下载事件

  9. 9

    如果应用程序被服务破坏,我如何保持下载文件运行(下载)?

  10. 10

    从闪亮的应用程序下载文件时如何设置您选择的文件名

  11. 11

    While循环锁定应用程序

  12. 12

    如何使用循环函数更新 python Kivy 应用程序

  13. 13

    更改时部署ASP.Net MVC,Angular应用程序下载文件

  14. 14

    从服务器下载文件时应用程序冻结

  15. 15

    如何从OS X应用程序中的URL下载文件

  16. 16

    应用程序从后台终止后是否可以继续下载文件

  17. 17

    从Blazor客户端应用程序从ASP.NET Core API下载文件

  18. 18

    下载文件后Blazor服务器端应用程序死亡

  19. 19

    从服务器下载文件的GraphQL / Apollo应用程序

  20. 20

    从请求中发送到django应用程序的url下载文件

  21. 21

    应用程序从后台终止后是否可以继续下载文件

  22. 22

    从命令行应用程序更改下载文件夹目标

  23. 23

    写入沙盒应用程序中的下载文件夹

  24. 24

    使用curl下载文件的C程序

  25. 25

    单击“下载”链接,使用JQuery不会下载文件

  26. 26

    Firefox下载种子使我没有打开它们的应用程序-只需打开下载文件夹

  27. 27

    Firefox下载种子使我没有打开它们的应用程序-只需打开下载文件夹

  28. 28

    tar文件并使用flask应用程序下载

  29. 29

    tar文件并使用flask应用程序下载

热门标签

归档