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.
So, I wanted to create an app that created tasks/habits in kivy. Basically, there would be a screen that shows you your tasks/habits, and you could click on a button to take you to another screen to create a new task/habit. You would input information about the task/habit in that screen, and click the submit button. The submit button would add the task/habit to the first screen. However, when I run my code, it works the first time. I can go to the second screen, add my habit/code and then go back to the first screen. However, when I click the button on the first screen, it gives me an error.
The error being: kivy.uix.screenmanager.ScreenManagerException: No Screen with name "second".
Here is my code:
main.py:
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.image import Image
from PIL import Image
import numpy as np
class FirstWindow(Screen):
def add_label(self, name, time, date):
label = Label(text= f' {name}, {time}, {date}')
self.ids.boxlayout.add_widget(label)
class SecondWindow(Screen):
a_task = False
a_habit = False
name = ""
time = ""
date = ""
def task_button(self):
self.a_task = True
self.a_habit = False
def habit_button(self):
self.a_habit = True
self.a_task = False
def submit_button(self):
self.name = self.ids.the_name.text
self.time = f'{self.ids.time_spinner_1.text}:{self.ids.time_spinner_2.text}'
self.date = f'{self.ids.date_spinner_1.text}/{self.ids.date_spinner_2.text}'
def get_name(self):
return self.name
def get_time(self):
return self.time
def get_date(self):
return self.date
kv = Builder.load_file('Button.kv')
class ButtonApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(FirstWindow())
sm.add_widget(SecondWindow())
return sm
if __name__ == '__main__':
ButtonApp().run()
Button.kv:
<FirstWindow>:
name: "first"
BoxLayout:
id: boxlayout
orientation: "vertical"
canvas.before:
Color:
rgba: (0.3,0.33,0.3,1)
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
Label:
text: "To Do List"
font_size: 32
pos_hint: { 'right': 0.65, 'top': 1.4 }
Button:
text: "add a task"
on_release: root.manager.current = "second"
<SecondWindow>:
name: "second"
BoxLayout:
orientation: "vertical"
spacing: "10dp"
canvas.before:
Color:
rgba: (0.3,0.33,0.3,1)
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
Label:
text: "Add A Task"
font_size: 32
pos_hint: { 'right': 0.65, 'top': 1.2 }
BoxLayout:
orientation: "horizontal"
Button:
text: "task"
on_press: root.task_button()
Button:
text: "habit"
on_press: root.habit_button()
TextInput:
id: the_name
text: "Name"
Label:
text: "alert"
BoxLayout:
orientation: "horizontal"
Spinner:
id: time_spinner_1
text: "00"
values: ['1','2','3','4','5','6','7','8','9','10','11', '12']
Spinner:
id: time_spinner_2
text: "00"
values: ['01','02','03','04','05','06','07','08','09','10','11', '12', '13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35','36','37','38','39','40','41','42','43','44','45','46','47','48','49','50','51','52','53','54','55','56','57','58','59']
BoxLayout:
orientation: "horizontal"
Spinner:
id: date_spinner_1
text: "00"
values: ['1','2','3','4','5','6','7','8','9','10','11', '12']
Spinner:
id: date_spinner_2
text: "00"
values: ['01','02','03','04','05','06','07','08','09','10','11', '12', '13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31']
Button:
text: "submit"
on_press: root.submit_button()
on_release:
root.manager.current = "first"
root.manager.get_screen("first").add_label(root.get_name(), root.get_time(), root.get_date())
Your code:
def submit_button(self):
self.name = self.ids.the_name.text
self.time = f'{self.ids.time_spinner_1.text}:{self.ids.time_spinner_2.text}'
self.date = f'{self.ids.date_spinner_1.text}/{self.ids.date_spinner_2.text}'
changes the name property of the SecondWindow Screen, so trying to change Screen to the second will no longer work. It looks like you are trying to use name for some other purpose. I suggest you use a variable with a different name.
I looked up kivy just today and I was just trying the widgets, everything worked fine until I used the TextInput and when I run it shows a black screen then notify me that python v3.9 stopped responding. When I remove the TextInput widget everything works fine again.
The main.py
from kivy.app import App
from kivy.properties import StringProperty, BooleanProperty
from kivy.uix.gridlayout import GridLayout
class WidgetsButtonClickExample(GridLayout):
my_text = StringProperty("0")
count = 0
is_on = BooleanProperty(False)
def on_button_click(self):
print("Button Clicked")
if self.is_on:
self.count += 1
self.my_text = str(self.count)
def on_toggle_button_state(self, toggle_button):
print("Toggle button state: " + toggle_button.state)
if toggle_button.state == "normal":
toggle_button.text = "OFF"
self.is_on = False
else:
toggle_button.text = "ON"
self.is_on = True
def switch_on_active(self, switch):
print("Switch: " + str(switch.active))
def on_slider_value(self, slider):
print("Slider value: " + str(int(slider.value)))
class TheLabApp(App):
pass
TheLabApp().run()
The .kv file
WidgetsButtonClickExample:
<WidgetsButtonClickExample>
cols: 3
ToggleButton:
text: "OFF"
on_state: root.on_toggle_button_state(self)
size_hint: None, 1
width: "100dp"
Button:
text: "Count"
on_press: root.on_button_click()
disabled: not root.is_on
Label:
text: root.my_text
font_name: "fonts/Lcd.ttf"
font_size: "50dp"
color: 1, .5, 1, .7
Switch:
id: my_switch
size_hint: None, 1
width: "100dp"
on_active: root.switch_on_active(self)
Slider:
disabled: not my_switch.active
id: my_slider
min: 0
max: 100
value: 50 # default value
# on_value: root.on_slider_value(self)
orientation: "horizontal" # v/h
BoxLayout:
orientation: "vertical"
Label:
text: str(int(my_slider.value))
# size_hint: 1, 1
ProgressBar:
max: 100 # min is always 0
value: my_slider.value
TextInput:
If I remove the last line of the .kv file everything works as expected. Can anyone help me with this?
I have started building a simple app using Kivy (and am in the process of moving over to KivyMD for aesthetic purposes) and have come across an issue where all of the elements I'm rendering to screen are rendering twice: The first time they are static and uninteractable and the second time are the interactable ones over the top. Im working with some ScrollViews with Buttons in them and when I scroll the buttons underneath are visible. There is also Labels with text that I update, these still show the default text underneath them.
screenshot of double rendering elements
main.py
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.scrollview import ScrollView
from kivy.uix.togglebutton import ToggleButton
from kivy.properties import NumericProperty, ObjectProperty
class MagnateCalcApp(App):
def build(self):
return Builder.load_file("magnatecalc.kv")
class CalcWindow(Screen):
current_value = NumericProperty(100)
current_price = NumericProperty(1)
pricelabel = ObjectProperty(None)
valuelabel = ObjectProperty(None)
money = ObjectProperty(None)
def update(self):
if self.current_price != 1:
val = float(self.current_price)/1000
self.pricelabel.text = "Price: " + str(val) + "M"
if self.current_value != 100:
self.valuelabel.text = "Multiplier: " + str(self.current_value)
if self.current_price != 1 and self.current_value != 100:
val = (float(self.current_value) * float(self.current_price))/1000
print(val)
self.money.text = "Value: " + str(val) + "M"
class RentWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
if __name__ == "__main__":
MagnateCalcApp().run()
magnatecalc.kv (usually has quite a lot of buttons in the ScrollView but the majority of these have been removed for readability)
WindowManager:
CalcWindow:
RentWindow:
<Button>:
font_size:35
size_hint:0.5,0.5
<CalcWindow>:
name: "Calc"
current_value: 100
current_price: 1
pricelabel: pricelabel
valuelabel: valuelabel
money: money
GridLayout:
cols:2
size: root.width, root.height
Label:
text:""
pos_hint:{"x":0, "top":1}
size_hint_y:0.15
size_hint_x:0.05
ScrollView:
do_scroll_y:False
do_scroll_x:True
pos_hint:{"x":1, "top":1}
size_hint_y:0.15
GridLayout: # here i want a scrollview
id: price
rows: 1
size_hint_x: None
width: self.minimum_width
ToggleButton:
text:"300K"
size_hint_x: None
on_press:
root.current_price = 300
root.update()
group:"price"
ToggleButton:
text:"400K"
size_hint_x: None
on_press:
root.current_price = 400
root.update()
group:"price"
ToggleButton:
text:"500K"
size_hint_x: None
on_press:
root.current_price = 500
root.update()
group:"price"
ToggleButton:
text:"600K"
size_hint_x: None
on_press:
root.current_price = 600
root.update()
group:"price"
ToggleButton:
text:"700K"
size_hint_x: None
on_press:
root.current_price = 700
root.update()
group:"price"
ToggleButton:
text:"800K"
size_hint_x: None
on_press:
root.current_price = 800
root.update()
group:"price"
ScrollView:
do_scroll_y:True
do_scroll_x:False
pos_hint:{"x":0, "top":0}
size_hint_x:0.075
GridLayout: # here i want a scrollview
id: multiplier
cols: 1
size_hint_y: None
height: self.minimum_height
ToggleButton:
text:"2"
size_hint_y: None
on_press:
root.current_value = 2
root.update()
group:"multiplier"
ToggleButton:
text:"3"
size_hint_y: None
on_press:
root.current_value = 3
root.update()
group:"multiplier"
ToggleButton:
text:"4"
size_hint_y: None
on_press:
root.current_value = 4
root.update()
group:"multiplier"
ToggleButton:
text:"5"
size_hint_y: None
on_press:
root.current_value = 5
root.update()
group:"multiplier"
ToggleButton:
text:"6"
size_hint_y: None
on_press:
root.current_value = 6
root.update()
group:"multiplier"
ToggleButton:
text:"7"
size_hint_y: None
on_press:
root.current_value = 7
root.update()
group:"multiplier"
GridLayout:
rows:2
pos_hint:{"x":1, "top":0}
GridLayout:
cols:2
Label:
id:pricelabel
text:"Price: "
font_size:50
Label:
id:valuelabel
text:"Multiplier: "
font_size:50
GridLayout:
cols:2
Label:
id:money
text:"Value: "
font_size:90
size_hint_x:1
pos_hint:{"x":0, "top":0}
Button:
text:"<- Rent"
pos_hint:{"x":1, "top":0}
size_hint: 0.25,0.25
on_release:
app.root.current = "Rent"
root.manager.transition.direction="right"
<RentWindow>:
name: "Rent"
Button:
text:"Go Back ->"
on_release:
app.root.current="Calc"
root.manager.transition.direction="left"
Is there anything obvious that I am missing in my .py that would cause this? This issue appeared when I started switching over to KivyMD but I have since reverted those changes to try and get back to the original functionality and I can't so have clearly broken something along the way.
Your kv file is being loaded twice, once explicitly by you with Builder.load_file and once automatically because it has the same name as your app class.
The simplest solution is to skip the manual load and just delete your build method.
I had the same problem as you, and I figured out how to build correctly the app to stop duplicate the items.
In kivymd this is the correct way to build the app:
class MagnateCalcApp(MDApp):
def build(self):
return super().build()
I don't know how but it recognises the correct kivy file.
I had this same thing occur after I was using pyinstaller to create a distribution. The build and dist directories created by the pyinstaller process contained copies of my .kv files. This was causing all the visual elements to appear multiple times depending on how many copies of the files were present in other directories.
Moving or deleting these directories solved the issue for me.
How do I properly create active properties for switch_id and switch_id_popup so I can create a conditional statement inside of timer_loop with kivy clock?
I got great feedback on a similar question(thanks again eyllanesc), but I am unable to incorporate advice now that popup is involved.
Below is a sketch that illustrates my issue. I have identified all of the areas in question with arrows. Thank you in advance for any help.
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
import time
from kivy.uix.popup import Popup
theRoot = Builder.load_string('''
<CustomPopup1>:
StackLayout:
active2: switch_id_popup.active #<---- switch_id_popup declared here(active2)
Switch: #<---- This switch (switch_id_popup)
id: switch_id_popup
size_hint: .5, .5
active: switch_id_popup.active
Button:
text: 'Close'
on_release: root.dismiss()
size_hint: .5, .5
StackLayout:
active1: switch_id.active #<---- switch_id declared here(active1)
orientation: 'lr-tb'
padding: 10
spacing: 5
Label:
text: "Zone 1 Valve"
size_hint: .25, .1
Switch: #<---- This switch (switch_id)
id: switch_id
size_hint: .25, .1
active: switch_id.active
Button:
text: "Program 1"
on_press: app.open_popup1()
size_hint: .5,.1
''')
class CustomPopup1(Popup):
pass
class theApp(App):
def build(self):
Clock.schedule_interval(self.timer_loop, 2)
return theRoot
def timer_loop(self, dt):
if theRoot.active1 and theRoot.active2: #<---- How do I make this work if switch_id_popup is within a popup?
print("Do something")
else:
print("Do nothing")
def open_popup1(self):
the_popup = CustomPopup1()
the_popup.open()
if __name__ == '__main__':
theApp().run()
As I mentioned in my previous solution, you should consider each class as a black box and expose properties that allow you to obtain and establish values. In the case of Popup, the active property must be part of the class and not the internal StackLayout. On the other hand in the open_popup method you are always creating a new Popup that will be deleted when you close it making the property is not accessible, so we deduce that there must be a Popup object with a larger scope for it must be created outside of theApp class or be a member of it. Lastly, active2 is not a property of theRoot.
Considering the above, the following solution is obtained:
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
import time
from kivy.uix.popup import Popup
theRoot = Builder.load_string('''
<CustomPopup>:
active: switch_id_popup.active
StackLayout:
Switch:
id: switch_id_popup
size_hint: .5, .5
Button:
text: 'Close'
on_release: root.dismiss()
size_hint: .5, .5
StackLayout:
active: switch_id.active
orientation: 'lr-tb'
padding: 10
spacing: 5
Label:
text: "Zone 1 Valve"
size_hint: .25, .1
Switch:
id: switch_id
size_hint: .25, .1
Button:
text: "Program 1"
on_press: app.open_popup()
size_hint: .5,.1
''')
class CustomPopup(Popup):
pass
class TheApp(App):
def build(self):
self.the_popup = CustomPopup()
Clock.schedule_interval(self.timer_loop, 2)
return theRoot
def timer_loop(self, dt):
if self.root.active and self.the_popup.active:
print("Do something")
else:
print("Do nothing")
def open_popup(self):
self.the_popup.open()
if __name__ == '__main__':
TheApp().run()