How to update kivy progress bar value from new thread?(如何从新线程更新Kivy进度条值?)
本文介绍了如何从新线程更新Kivy进度条值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我有这个图像下载器,作为新的线程和弹出式窗口,其中包含进度条。进度条在下载过程中不会更新,但在下载之后(下载器是用请求编写的,gui应用程序是用kivy制作的)。有什么办法解决这个问题吗? 下载器: 它被分隔在另一个文件中
class Downloader(threading.Thread):
def __init__(self, url: str, download_monitor):
super(Downloader, self).__init__(daemon=True) # daemon dies when main die
self.url = url
self.download_monitor = download_monitor # url popup
def run(self) -> None:
# Reset
self.download_monitor.reset()
file_name = self.url.split('/')[-1]
# Less RAM usage
with requests.get(self.url, stream=True) as req: # stream=True not to read at once
req.raise_for_status()
with open('temp/'+file_name, 'wb') as file:
chunks = list(enumerate(req.iter_content(chunk_size=8192)))
self.download_monitor.downloading_progress.max = chunks[-1][0] # last element
for progress, chunk in chunks:
self.download_monitor.downloading_progress.value = progress
file.write(chunk)
弹出.py: 它被分隔在另一个文件中
class UrlPopup(Popup):
url_input = ObjectProperty()
downloading_progress = ObjectProperty()
def __init__(self, **kwargs):
super(UrlPopup, self).__init__(**kwargs)
def download(self):
# https://www.nasa.gov/sites/default/files/thumbnails/image/hubble_ngc2903_potw2143a.jpg.jpg
if self.url_input.text.startswith('https://'): # if it is url address
download(self.url_input.text, self)
def on_dismiss(self):
self.reset()
self.url_input.text = ''
def reset(self):
self.downloading_progress.max = 0
self.downloading_progress.value = 0
弹出.kv: 它被分隔在另一个文件中
<UrlPopup>:
url_input: url_input
downloading_progress: downloading_progress
id: downloader
title: 'URL address'
size_hint: .25, None
height: 157
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: 64
TextInput:
id: url_input
multiline: False
size_hint_y: None
height: 32
font_size: 16
ProgressBar:
id: downloading_progress
size_hint_y: None
height: 32
BoxLayout:
orientation: 'horizontal'
size_hint_y: None
height: 32
Button:
text: 'Download'
on_press: root.download()
Button:
text: 'Close'
on_press: root.dismiss()
EDIT1 ApuCoder我按照你写的做了,但下载后进度仍在更新。 还有别的主意吗? Popup.py:
class UrlPopup(Popup):
url_input = ObjectProperty()
downloading_progress = ObjectProperty()
progress_value = NumericProperty()
def update_progress(self, dt):
self.progress_value += 1
下载程序.py:
with requests.get(self.url, stream=True) as req: # stream=True not to read at once
req.raise_for_status()
with open('temp/'+file_name, 'wb') as file:
chunks = list(enumerate(req.iter_content(chunk_size=8192)))
self.download_monitor.downloading_progress.max = chunks[-1][0] # last element
Clock.schedule_interval(self.download_monitor.update_progress, .1)
for progress, chunk in chunks:
#self.download_monitor.downloading_progress.value = progress
file.write(chunk)
弹出.kv:
ProgressBar:
id: downloading_progress
value: root.progress_value
size_hint_y: None
height: 32
EDIT2 这与类Downloader在同一个文件中。我在按下按钮时调用此函数
def download(url: str, download_monitor):
"""Other thread"""
downloader = Downloader(url, download_monitor)
downloader.start()
推荐答案
假设您要下载一些内容并显示Kivy中正在进行的进程(或当前状态),我更新并修改了您的一些代码以创建一个最小的示例。
在这种情况下,不需要创建新的Thread
类,而是每次都创建一个新的线程对象,并将target
设置为用于在磁盘中读取和写入二进制数据的某种方法(这里是start_download
)。因此,可以在此方法内控制进度,从而不需要调度。
from threading import Thread
import requests
from kivy.app import runTouchApp
from kivy.lang import Builder
from kivy.properties import (
BooleanProperty,
NumericProperty,
ObjectProperty,
)
from kivy.uix.popup import Popup
from kivy.uix.screenmanager import Screen
Builder.load_string("""
<DownLoadScreen>:
Button:
text: "Open Downloader"
on_release: root.open_downloader()
<UrlPopup>:
url_input: url_input
title: 'URL address'
size_hint: .75, None
height: "450dp"
BoxLayout:
orientation: "vertical"
TextInput:
id: url_input
text: "https://www.nasa.gov/sites/default/files/thumbnails/image/hubble_ngc2903_potw2143a.jpg.jpg"
multiline: False
size_hint_y: None
height: "64dp"
font_size: "16sp"
ProgressBar:
pos_hint: {"center_x" : 0.5}
value: root.prog_val
max: root.tot_size
Label:
id: lbl
text: "Downloading file...({:.0%})".format(root.prog_val/root.tot_size) if root.has_started else ""
BoxLayout:
size_hint_y: None
height: dp(48)
Button:
text: 'Download'
on_release: root.download()
Button:
text: 'Close'
on_press: root.dismiss()
""")
class UrlPopup(Popup):
url_input = ObjectProperty()
prog_val = NumericProperty(0) # To capture the current progress.
tot_size = NumericProperty(1) # Total size of the file/content. Setting the default value to 1 to avoid ZeroDivisionError, though will not affect anyhow.
has_started = BooleanProperty(False) # Just to manipulate the label text.
def start_download(self):
self.has_started = True
self.url = self.url_input.text
# file_name = self.url.split('/')[-1]
with requests.get(self.url, stream=True) as req:
if req.status_code == 200: # Here, you can create the binary file.
# chunks = list(enumerate(req.iter_content(chunk_size=8192))) # This may take more memory for larger file.
self.tot_size = int(req.headers["Content-Length"])
item_size = 2048 # Reducing the chunk size increases writing time and so needs more time in progress.
for i, chunk in enumerate(req.iter_content(chunk_size = item_size)):
self.prog_val = i*item_size
# file.write(chunk)
self.ids.lbl.text = "Download completed." # A confirmation message.
def download(self):
"""A new thread object will be created each time this method is revoked. But be careful about the threads already created."""
Thread(target = self.start_download).start()
def on_dismiss(self):
self.url_input.text = ""
self.has_started = False
class DownLoadScreen(Screen):
def open_downloader(self):
UrlPopup().open()
runTouchApp(DownLoadScreen())
如果符合您的需要,请让我知道。
这篇关于如何从新线程更新Kivy进度条值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
沃梦达教程
本文标题为:如何从新线程更新Kivy进度条值?
猜你喜欢
- 如何命名HDF5数据集中的列? 2022-09-21
- 获取多索引中某个级别的最后一个元素 2022-09-22
- 如何将属性添加到作为组存储在HDF5文件中的 pa 2022-09-21
- 如何防止Groupby超越指数? 2022-09-22
- 使用带有CROSS_VAL_SCORE的自定义估计器失败 2022-09-21
- 为什么切换屏幕在Kivy中不起作用? 2022-09-21
- 将文件从Azure文件加载到Azure数据库 2022-09-21
- 基于多个一级列的子集多索引DataFrame 2022-09-22
- H5py:如何在HDF5组和数据集上使用key()循环 2022-09-21
- 合并具有多个索引和列值的数据帧 2022-09-22