kivymd MDProgressBar UI 即使使用线程也不更新
kivymd MDProgressBar UI not updating even with threading
我在 test.py 和 test.kv 中有以下代码。
MDProgressBar UI 直到程序结束才移动。我在 Whosebug 中读过类似的问题,但发布的解决方案只是片段。
假设self.process_some_data()是一个需要很长时间才能完成的函数,MDProgressBar UI实例self.progress_bar 应该反映当前的进度。根据其他论坛帖子的解决方案,我
- 为 self.process_some_data() 函数创建了一个线程。
- 使用 Clock.schedule_once() 作为 self.update_progress_bar() 函数更新 self.progress_bar.value 在主线程中处于不同的完成阶段。
- 为 self.update_progress_bar() 函数包含装饰器@mainthread,这似乎没有任何区别。
随时编辑代码并重新发布完整的解决方案。谢谢
main.py
from kivymd.app import MDApp
from kivymd.uix.progressbar import MDProgressBar
from kivy.clock import Clock
from kivy.uix.popup import Popup
from kivymd.uix.dialog import MDDialog
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
import time
import threading
from kivy.clock import mainthread
from functools import partial
class Screen1(Screen):
def show_popup(self):
self.progress_bar = MDProgressBar()
self.popup = Popup(
title ='Progress',
content = self.progress_bar,
auto_dismiss = False, # dialog does NOT close if click outside it
size_hint = (None, None),
size = (400, 400)
)
self.popup.bind( on_open = lambda x: self.run_thread() )
# self.progress_bar.max = 100
self.progress_bar.value = 10
self.popup.open()
print(self.progress_bar.value)
@mainthread
def update_progress_bar(self, val, _):
self.progress_bar.value = val
print(self.progress_bar.value)
if val >= 100:
# self.popup.dismiss()
dialog = MDDialog(title="Status", text="Completed")
dialog.open()
def run_thread(self):
t1 = threading.Thread(target=self.process_some_data())
t1.start()
# t1.join()
def process_some_data(self):
time.sleep(1) # simulate program is running something
Clock.schedule_once(partial(self.update_progress_bar, 25), 0)
time.sleep(1) # simulate program is running something
Clock.schedule_once(partial(self.update_progress_bar, 50), 0)
time.sleep(1) # simulate program is running something
Clock.schedule_once(partial(self.update_progress_bar, 75), 0)
time.sleep(1) # simulate program is running something
Clock.schedule_once(partial(self.update_progress_bar, 100), 0)
# Create the App class
class MyApp(MDApp):
def build(self):
return Builder.load_file("test.kv")
# run the App
if __name__ in ("__main__"):
MyApp().run()
test.kv
Screen1:
Button:
text: "Run program"
on_release: root.show_popup()
size_hint: 0.4, 0.1
pos_hint: {"center_x": 0.5, "center_y": 0.5}
在您的 run_thread()
方法中,行:
t1 = threading.Thread(target=self.process_some_data())
运行 process_some_data()
方法,然后将创建的线程的目标设置为该方法的 return。我认为您只需要从该方法中删除 ()
,以便将目标设置为 process_some_data
方法而不是其 return:
t1 = threading.Thread(target=self.process_some_data)
我在 test.py 和 test.kv 中有以下代码。 MDProgressBar UI 直到程序结束才移动。我在 Whosebug 中读过类似的问题,但发布的解决方案只是片段。
假设self.process_some_data()是一个需要很长时间才能完成的函数,MDProgressBar UI实例self.progress_bar 应该反映当前的进度。根据其他论坛帖子的解决方案,我
- 为 self.process_some_data() 函数创建了一个线程。
- 使用 Clock.schedule_once() 作为 self.update_progress_bar() 函数更新 self.progress_bar.value 在主线程中处于不同的完成阶段。
- 为 self.update_progress_bar() 函数包含装饰器@mainthread,这似乎没有任何区别。
随时编辑代码并重新发布完整的解决方案。谢谢
main.py
from kivymd.app import MDApp
from kivymd.uix.progressbar import MDProgressBar
from kivy.clock import Clock
from kivy.uix.popup import Popup
from kivymd.uix.dialog import MDDialog
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
import time
import threading
from kivy.clock import mainthread
from functools import partial
class Screen1(Screen):
def show_popup(self):
self.progress_bar = MDProgressBar()
self.popup = Popup(
title ='Progress',
content = self.progress_bar,
auto_dismiss = False, # dialog does NOT close if click outside it
size_hint = (None, None),
size = (400, 400)
)
self.popup.bind( on_open = lambda x: self.run_thread() )
# self.progress_bar.max = 100
self.progress_bar.value = 10
self.popup.open()
print(self.progress_bar.value)
@mainthread
def update_progress_bar(self, val, _):
self.progress_bar.value = val
print(self.progress_bar.value)
if val >= 100:
# self.popup.dismiss()
dialog = MDDialog(title="Status", text="Completed")
dialog.open()
def run_thread(self):
t1 = threading.Thread(target=self.process_some_data())
t1.start()
# t1.join()
def process_some_data(self):
time.sleep(1) # simulate program is running something
Clock.schedule_once(partial(self.update_progress_bar, 25), 0)
time.sleep(1) # simulate program is running something
Clock.schedule_once(partial(self.update_progress_bar, 50), 0)
time.sleep(1) # simulate program is running something
Clock.schedule_once(partial(self.update_progress_bar, 75), 0)
time.sleep(1) # simulate program is running something
Clock.schedule_once(partial(self.update_progress_bar, 100), 0)
# Create the App class
class MyApp(MDApp):
def build(self):
return Builder.load_file("test.kv")
# run the App
if __name__ in ("__main__"):
MyApp().run()
test.kv
Screen1:
Button:
text: "Run program"
on_release: root.show_popup()
size_hint: 0.4, 0.1
pos_hint: {"center_x": 0.5, "center_y": 0.5}
在您的 run_thread()
方法中,行:
t1 = threading.Thread(target=self.process_some_data())
运行 process_some_data()
方法,然后将创建的线程的目标设置为该方法的 return。我认为您只需要从该方法中删除 ()
,以便将目标设置为 process_some_data
方法而不是其 return:
t1 = threading.Thread(target=self.process_some_data)