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