I want a ProgressBar to start loading automatically when opening the application (similar to a loading screen). I have already created the bar. However, I've been trying to get the automatic loading process for two days. Does one of you have an idea?
Thanks in advance!
py-file:
from kivy.uix.screenmanager import ScreenManager
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.clock import Clock
#Window.size = (1366, 768)
#Window.fullscreen = True
class GATR(MDApp):
def build(self):
global sm
sm = ScreenManager()
sm.add_widget(Builder.load_file("splash.kv"))
sm.add_widget(Builder.load_file("login.kv"))
return sm
def on_start(self):
Clock.schedule_once(self.login, 5)
def login(*args):
sm.current = "login"
if __name__=="__main__":
GATR().run()
kv-file (The file with the progress bar):
MDScreen:
name: "splash"
MDFloatLayout:
md_bg_color: 110/255, 123/255, 139/255, 1
Image:
source: "logo.png"
size: 50, 50
pos_hint: {"center_x":.5, "center_y":.6}
MDLabel:
text: "Text"
text_color: 255, 255, 255, 0
font_size: "60sp"
pos_hint: {"center_x":.51, "center_y":.25}
halign: "center"
font_name: "3.ttf"
ProgressBar:
id: pb
min: 0
max: 100
pos_hint: {"center_x": .5, "center_y": .1}
size_hint_x: .8
I think something like this should do the work.
def foo(self):
current = self.ids.pb.value #get current value of the progress bar
if current >= 100: #check when it hits 100%, stop it
return False
current += 1 #increment current value
self.ids.pb.value = current #update progress bar value
def on_start(self):
Clock.schedule_interval(self.foo, 1/25) #kivy clock object to time it
It is just an idea, you should play around with it and implement it correctly with your codebase.
Related
I'm making a stopwatch using Kivy that includes "Minutes, seconds, milliseconds".
But the problem is that the Clock method doesn't seem to support the shorter time below 0.02. So no matter what numbers you give, it still can not catch up with the milliseconds' change and counting time slower than the real-time (You can see it clearly in my code below).
So is there any better way to update my Kivy's GUI by milliseconds, so I can display the numbers on my app's screen?
Here's the code I extracted from my main source:
from kivy.uix.relativelayout import RelativeLayout
from kivy.lang import Builder
from kivy.clock import Clock
from functools import partial
Builder.load_string("""
<ModifyTime>:
id: name
BoxLayout:
id: time
spacing: 1
size_hint_y: None
height: minute.height
TextInput:
id: minute
hint_text: "Minutes"
size_hint: None,None
width: time_scale.texture_size[0] + dp(14)
height: time_scale.texture_size[1] + dp(12)
multiline: False
TextInput:
id: second
hint_text: "Seconds"
size_hint: None,None
width: time_scale.texture_size[0] + dp(14)
height: time_scale.texture_size[1] + dp(12)
multiline: False
TextInput:
id:milisecond
hint_text: "Miliseconds"
size_hint: None,None
width: time_scale.texture_size[0] + dp(14)
height: time_scale.texture_size[1] + dp(12)
multiline: False
Button:
text: "Activate stopwatch"
on_release:
root.activate_stopwatch(root)
Label:
id: time_scale
opacity: 0
text: "00:00:00"
size_hint: None,None
size: 0,0
""")
class ModifyTime(RelativeLayout):
def __init__(self,**kwargs):
super().__init__(**kwargs)
def activate_stopwatch(self,watch):
watch.ids.minute.text="0"
watch.ids.second.text="0"
watch.ids.milisecond.text="0"
self.stopwatch=Clock.schedule_interval(partial(self._time_update,watch),0.001)
def _time_update(self,watch,dt):
watch.ids.milisecond.text=str(int(watch.ids.milisecond.text)+1)
self._time_update_calculate(watch)
def _time_update_calculate(self,watch):
if watch.ids.milisecond.text == "1000":
watch.ids.milisecond.text = "0"
watch.ids.second.text=str(int(watch.ids.second.text)+1)
if watch.ids.second.text == "60":
watch.ids.second.text == "0"
watch.ids.minute.text=str(int(watch.ids.minute.text)+1)
if __name__ == "__main__":
from kivy.app import App
class TestApp(App):
def build(self):
return ModifyTime()
TestApp().run()
I modified your .py code to the following which should fairly count upto milliseconds (should work without any changes in config).
class ModifyTime(RelativeLayout):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.milisec = 0
def activate_stopwatch(self,watch):
watch.ids.minute.text="0"
watch.ids.second.text="0"
watch.ids.milisecond.text="0"
self.stopwatch=Clock.schedule_interval(partial(self._time_update,watch),0.001)
def _time_update(self,watch,dt):
self.milisec += 1000*dt
sec, mili = divmod(self.milisec, 1000)
mint, sec = divmod(sec, 60)
watch.ids.milisecond.text = str(int(mili))
watch.ids.second.text = str(int(sec))
watch.ids.minute.text = str(int(mint))
if __name__ == "__main__":
from kivy.app import App
class TestApp(App):
def build(self):
return ModifyTime()
TestApp().run()
I'm making a meditation app with kivymd, and I'm trying to figure out how to connect a audio file to a progress bar. There are not too many videos on how to do it, so any help would be greatly appreciated, thanks.
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivymd.app import MDApp
from kivy.core.window import Window
Window.size = (400, 800)
class SecondWindow(Screen):
def play_sound(self):
sound = SoundLoader.load("audio2/mp3.mp3")
if sound:
sound.play()
sm = ScreenManager()
sm.add_widget(FirstWindow(name="First"))
sm.add_widget(SecondWindow(name="Second"))
class MainApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "BlueGray"
return Builder.load_file("thelab.kv")
MainApp().run()
kivy file -
<SecondWindow>:
MDIconButton:
id: my_sound
icon: "play"
user_font_size: 150
pos: 100, 100
on_press:
root.play_sound()
MDProgressBar:
id: progress_bar
size_hint: .8, .5
pos: 90, 200
min: 0
max: 100
You have to handle it yourself. For that you can use Clock.schedule_interval to update the MDProgressBar.value.
First create prop. in your SecondWindow to bind to the prop. of MDProgressBar. Then schedule a callback say, update_progress to update the current progress. I also included the end case when the audio stops playing.
class SecondWindow(Screen):
length = NumericProperty(0.0)
progress = NumericProperty(0.0)
def play_sound(self):
sound = SoundLoader.load("audio2/mp3.mp3")
if sound:
self.length = sound.length
sound.play()
# Now schedule and start updating after every 1.0 sec.
# Use 'Clock.create_trigger' for more control.
self.prog_ev = Clock.schedule_interval(self.update_progress, 1.0)
def update_progress(self, dt):
if self.progress < self.length:
self.progress += 1 # Update value.
else: # End case.
self.progress = 0 # Reset value.
self.prog_ev.cancel() # Stop updating.
Now the binding work in kvlang; here also I added required logic to change icon automatically.
<SecondWindow>:
MDIconButton:
id: my_sound
icon: "pause" if root.progress else "play"
user_font_size: 150
pos: 100, 100
on_press:
root.play_sound()
MDProgressBar:
id: progress_bar
size_hint: .8, .5
pos: 90, 200
min: 0
max: root.length
value: root.progress
so i'm learning kivy and I want to have a button bring me to a different screen to be able to set a alarm. I've made another file to learn how to transition between screens and its worked and all morning I've been trying to get it to work in my other app and I cant figure out why it wont work in this app. The app works and runs but when I click the button nothing happens. For anyone reading and helping me I appreciate it.
python file
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.screenmanager import ScreenManager, Screen
import time
class AlarmWindow(Screen):
pass
class ClockScreen(Screen):
def addAlarm(self):
print("add alarm")
class WindowManager(ScreenManager):
pass
Builder.load_file('myApp.kv')
class ClockApp(App):
def build(self):
return ClockScreen()
def on_start(self):
Clock.schedule_interval(self.updateClock, 1)
def updateClock(self, *args):
print(args)
#create time variable, if var doesnt work here create it in the ClockScreen class and call it here
hour = time.strftime("%H")
minute = time.strftime("%M")
clockTime = f'{hour}:{minute}'
#update label
self.root.ids.clock.text = clockTime
ca = ClockApp()
ca.run()
kv file
WindowManager:
ClockScreen:
AlarmWindow:
<ClockScreen>:
name: "main"
FloatLayout:
size: root.width, root.height
Label:
id: clock
text: "12:00"
font_size: 32
Button:
text: "Add Alarm"
size_hint: None, None
size: 150, 100
pos_hint: {'center_x': .5, 'center_y': 0.3}
on_release: app.root.current = 'second'
<AlarmWindow>:
name: "second"
FloatLayout:
size: root.width, root.height
Label:
text: "Create alarm here"
Button:
text: "Go Back"
on_release: app.root.current = 'main'
im currently looking into kivy to start with crossplatform development. i have a bit of python experience (but basic) and now wanted to code a little game in kivy to get into. i probably wont finish this but i like learning stuff while doing it with something im intrested in.
Anyway my "App" is supposed to be seperated in two seperate "screens" the top one is only used for displaying stuff and the all interactive stuff is controlled from the bottom "screen".
Now i want to display some text in old school way by getting it written letter by letter to the screen.
This is working fine but for some reason the Label widget is only updated on screen if i call the "print_something" function from the top screen, if i call it from the bottom screen the function is indeed called but the Label widget wont change on screen.
Am i doing something wrong?
Here is a stripped version of the code:
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.clock import Clock
Builder.load_string('''
<MainUI>:
orientation: 'vertical'
# both these variables can be the same name and this doesn't lead to
# an issue with uniqueness as the id is only accessible in kv.
<Screen1>:
print_txt: print_txt
layout: layout
RelativeLayout:
id: layout
pos: 0, 400
size: 480, 400
Button:
pos: 0, 200
size_hint: (1, 0.2)
text: "Test Print"
on_press: root.print_something('TEST PRINT FROM SCREEN1')
AnchorLayout:
anchor_x: 'center'
anchor_y: 'bottom'
Label:
id: print_txt
padding_x: 10
markup: True
text_size: self.size
halign: 'left'
valign: 'top'
size_hint: (1, 0.2)
text: ""
<Screen2>:
btn1: btn1
RelativeLayout:
pos: 0, 0
size: 480, 400
Button:
id: btn1
pos_hint: {'x': .15, 'center_y': .5}
size_hint: (0.7, 0.5)
text: "Test Print"
on_press: root.print_text()
''')
class Screen1(Widget):
print_txt = ObjectProperty(None)
layout = ObjectProperty(None)
def print_something(self, string):
print 'Function called...'
self.print_txt.text = ''
counter = [0]
string_len = len(string)
def print_step(dt):
if counter[0] == string_len:
return False
else:
self.print_txt.text += string[counter[0]]
counter[0] = counter[0] + 1
Clock.schedule_interval(print_step, 2.0/60.0)
print 'Function End..'
class Screen2(Widget):
btn1 = ObjectProperty(None)
def __init__(self):
super(Screen2, self).__init__()
def print_text(self):
print 'Trying to print Text from Screen2 to Screen1'
target = Screen1()
target.print_something('TEST PRINT FROM SCREEN2')
class MainUI(Widget):
def __init__(self):
super(MainUI, self).__init__()
self.screen1 = Screen1()
self.add_widget(self.screen1)
self.add_widget(Screen2())
class MainApp(App):
def build(self):
Window.size = (480, 800)
return MainUI()
if __name__ == '__main__':
MainApp().run()
Your Screen2 print_text method creates a new Screen1 instance, which is modified but not displayed anywhere so you don't see anything change.
You could change the call to instead something like
on_press: root.parent.screen1.print_text()
...to access the print_text function of the Screen1 instance that you actually want to update.
Problem is with screenmanager where i have 2 screens say loadingscreen and menuscreen .
In starting I load loading screen first and after 3 seconds i switch it to menuscreen which help of clock schedule .
On menu screen I have a button which when pressed takes us back to loading screen .
Now i want to move back to menu screen after 3 seconds of loading screen is active .. Can someone suggest best way to do it . Below is a code which explains what i have and what i need :
I know changing below code to have Clock.schedule_interval(self.callNext, 3) in LoadingScreen Class will do the job but i am looking for a better option which is much more efficient
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen,FallOutTransition
from kivy.properties import ObjectProperty,NumericProperty
from kivy.uix.image import Image
from kivy.graphics import Color
from kivy.clock import Clock
gui_v3 = '''
<PlayScreen>:
play_Button: playButton
canvas.before:
Color:
rgb: (0, 0, 1)
GridLayout:
rows:1
size_hint: .1,.1
pos_hint: {'center_x': .5, 'center_y': .5}
Button:
id: playButton
size_hint_x: None
width: 100
text: 'Play !'
font_size: 12
bold: True
italic: False
border: 10,10,10,10
color: (0.5, 1, 0.5, 1)
on_press: root.playButton_press()
<LoadingScreen>:
canvas:
Color:
rgba: 0.4, 0.4, 0.4, 1
Rectangle:
pos: root.center
size: (32, 32)
BoxLayout:
Label:
text: 'JB'
font_size: 100
Label:
text: 'Loading...'
font_size: 10
'''
class PlayScreen(Screen):
play_Button = ObjectProperty(None)
def __init__(self, **kwargs):
super(PlayScreen, self).__init__(**kwargs)
Clock.schedule_interval(self.update, 1.0/2)
def update(self,dt):
print "Current screen is ",self.manager.current
def playButton_press(self):
print "Hi Play button is pressed"
sm.current = 'loading'
class LoadingScreen(Screen):
def __init__(self, **kwargs):
super(LoadingScreen, self).__init__(**kwargs)
Clock.schedule_once(self.callNext, 3)
def callNext(self,dt):
self.manager.current = 'play'
print "Hi this is call Next Function of loading 1"
# Create the screen manager
Builder.load_string(gui_v3)
sm = ScreenManager(transition= FallOutTransition())
sm.add_widget(LoadingScreen(name='loading'))
sm.add_widget(PlayScreen(name='play'))
class MyJB(App):
def build(self):
print sm.screen_names
return sm
if __name__ == '__main__':
MyJB().run()
You should use the screen's on_enter event. Simply do this in the kv file:
<LoadingScreen>:
on_enter: Clock.schedule_once(self.callNext, 3)
Also a the top of the kv you need to import Clock, #:import Clock kivy.clock.Clock. Now every time the screen is opened it'll schedule the callback.