New to Python and Kivy. The issue might be not understanding how the main thread of Kivy works, or how to add to the main thread.
The following is made-up code to demonstrate the current problem.
import os import threading import http.server import socketserver from time import sleep import kivy from kivy.app import App from kivy.clock import Clock from kivy.lang import Builder from kivy.properties import NumericProperty from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition Builder.load_string(""" <BootstrapScreen>: name: 'BootstrapScreen' Label: ProgressBar: id: progress_bar max: 5 size: root.width / 2, 300 center_x: self.parent.center_x center_y: self.parent.center_y <StartScreen>: name: 'StartScreen' Label: ProgressBar: id: progress_bar max: 5 size: root.width / 2, 300 center_x: self.parent.center_x center_y: self.parent.center_y """) class BootstrapScreen(Screen): progress_bar_value = NumericProperty(0) def on_enter(self): Clock.schedule_interval(self.update_progress_bar, 1) Clock.schedule_once(self.start_server, 0) def update_progress_bar(self, dt): if self.progress_bar_value < 5: self.progress_bar_value += 1 else: self.login() return False self.ids.progress_bar.value = self.progress_bar_value def start_server(self, dt): sleep(10) self.host = '127.0.0.1' self.port = 9999 self.server = socketserver.TCPServer( (self.host, self.port), http.server.SimpleHTTPRequestHandler ) self.server_thread = threading.Thread(target=self.server.serve_forever) self.server_thread.daemon = True self.server_thread.start() def login(self): App().stop() class StartScreen(Screen): progress_bar_value = NumericProperty(0) def on_enter(self): Clock.schedule_interval(self.update_progress_bar, 1) def update_progress_bar(self, dt): if self.progress_bar_value < 5: self.progress_bar_value += 1 else: self.bootstrap() return False self.ids.progress_bar.value = self.progress_bar_value def bootstrap(self): if not self.manager.has_screen('BootstrapScreen'): self.manager.add_widget(BootstrapScreen()) self.manager.current = 'BootstrapScreen' class DuoApp(App): def build(self): screen_manager = ScreenManager(transition=NoTransition()) screen_manager.add_widget(StartScreen()) return screen_manager if __name__ == '__main__': DuoApp().run()
The application starts on a first screen. On the first screen is a progress bar that starts automatically and, in about five seconds, the application goes to the second screen. On the second screen, there is another progress bar that is supposed to start immediately and also last for about five seconds, but it waits until after the server starts before beginning. (The sleep(10)
is there solely for dramatic affect to demonstrate how the progress bar does not start immediately upon entering the screen, and because the actual process takes about ten seconds to complete.)
How would one go about making the progress bar update in the window at the same time as start_server
(or any other background process that takes ten seconds to complete) in the background?
Advertisement
Answer
Via adywizard over on Reddit …
# import os import threading import http.server import socketserver from time import sleep # import kivy from kivy.app import App from kivy.clock import Clock from kivy.lang import Builder from kivy.properties import NumericProperty from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition Builder.load_string(""" <BootstrapScreen>: name: 'BootstrapScreen' Label: ProgressBar: id: progress_bar max: 5 size: root.width / 2, 300 center_x: self.parent.center_x center_y: self.parent.center_y <StartScreen>: name: 'StartScreen' Label: ProgressBar: id: progress_bar max: 5 size: root.width / 2, 300 center_x: self.parent.center_x center_y: self.parent.center_y """) class BootstrapScreen(Screen): progress_bar_value = NumericProperty(0) def on_enter(self): Clock.schedule_interval(self.update_progress_bar, 1) # Clock.schedule_once(self.start_server, 0) # Create a separate thread instead. threading.Thread( target=self.start_server, daemon=True ).start() def update_progress_bar(self, dt): if self.progress_bar_value < 5: self.progress_bar_value += 1 else: self.login() return False self.ids.progress_bar.value = self.progress_bar_value def start_server(self): sleep(10) self.host = '127.0.0.1' self.port = 9999 self.server = socketserver.TCPServer( (self.host, self.port), http.server.SimpleHTTPRequestHandler ) self.server_thread = threading.Thread(target=self.server.serve_forever) self.server_thread.daemon = True self.server_thread.start() def login(self): App().stop() class StartScreen(Screen): progress_bar_value = NumericProperty(0) def on_enter(self): Clock.schedule_interval(self.update_progress_bar, 1) def update_progress_bar(self, dt): if self.progress_bar_value < 5: self.progress_bar_value += 1 else: self.bootstrap() return False self.ids.progress_bar.value = self.progress_bar_value def bootstrap(self): if not self.manager.has_screen('BootstrapScreen'): self.manager.add_widget(BootstrapScreen()) self.manager.current = 'BootstrapScreen' class DuoApp(App): def build(self): screen_manager = ScreenManager(transition=NoTransition()) screen_manager.add_widget(StartScreen()) return screen_manager if __name__ == '__main__': DuoApp().run()