Reputation: 35
I wanted to make a quick dirty app for my guitar practise (why not?) and decided to use Kivy with no prior Kivy experience. It is a very simple app (in a very badly written code) with two screens and a selection of chords to iterate through. User selects the chords (ToggleButtons) he wants to practise and these chords are then upon hitting the "accept" button iteratively animated at a second screen at user's given time interval.
However, I am having the trouble of animating the "infinitely changing label" on the second screen with chords. How do I do this? Also, how do I pass the values (user's selected chords and minutes) from the first screen to the label in the second screen?
Any help is much appreciated. Hopefully, the solution should be very easy to someone experienced in Kivy. Here is my take (not working properly):
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.stacklayout import StackLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.animation import Animation
from kivy.clock import Clock
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super(MyGrid, self).__init__(**kwargs)
self.sel_chords = []
self.time = 0
self.cols = 1
self.add_widget(Label(text="Please, select the chords you would like to practise."))
self.intro = StackLayout()
self.A = ToggleButton(text = "A", size_hint=(.2,.2))
self.intro.add_widget(self.A)
self.E = ToggleButton(text = "E", size_hint=(.2,.2))
self.intro.add_widget(self.E)
self.C = ToggleButton(text = "C", size_hint=(.2,.2))
self.intro.add_widget(self.C)
self.D = ToggleButton(text = "D", size_hint=(.2,.2))
self.intro.add_widget(self.D)
self.G = ToggleButton(text = "G", size_hint=(.2,.2))
self.intro.add_widget(self.G)
self.Cadd9 = ToggleButton(text = "Cadd9", size_hint=(.2,.2))
self.intro.add_widget(self.Cadd9)
self.add_widget(self.intro)
self.outro = GridLayout(cols=3)
self.outro.add_widget(Label(text="Seconds per chord:"))
self.minutes = TextInput(multiline=False)
self.outro.add_widget(self.minutes)
self.submit = Button(text="Accept", font_size=40)
self.submit.bind(on_press=self.pressed)
self.outro.add_widget(self.submit)
self.add_widget(self.outro)
def pressed(self, instance):
if self.A.state == "down":
self.sel_chords.append("A")
if self.C.state == "down":
self.sel_chords.append("C")
if self.D.state == "down":
self.sel_chords.append("D")
if self.E.state == "down":
self.sel_chords.append("E")
if self.G.state == "down":
self.sel_chords.append("G")
if self.Cadd9.state == "down":
self.sel_chords.append("Cadd9")
try:
self.time = int(self.minutes.text)
except:
pass
print(self.time)
self.time = 0
self.sel_chords = []
class MyGrid2(GridLayout):
def __init__(self, **kwargs):
super(MyGrid2, self).__init__(**kwargs)
self.cols = 1
self.rows = 2
self.temp = "A"
self.lbl = Label(text="A")
self.lbl.font_size = '300dp'
self.add_widget(self.lbl)
self.back = Button(text="Back", font_size=40)
self.add_widget(self.back)
#for element in itertools.cycle(["A", "B"]):
# self.lbl.text = element
def update_lbl(time):
pass #update lbl to the chords
Clock.schedule_interval(update_lbl, 1)
class MyScreenManager(ScreenManager):
def __init__(self, **kwargs):
super(MyScreenManager, self).__init__(**kwargs)
self.main_screen = Screen(name="main_screen")
self.new_screen = Screen(name="new_screen")
self.add_widget(self.main_screen)
self.add_widget(self.new_screen)
main_grid = MyGrid()
main_grid.submit.bind(on_press=self.next_screen)
self.main_screen.add_widget(main_grid)
next_grid = MyGrid2()
next_grid.back.bind(on_press=self.back_screen)
self.new_screen.add_widget(next_grid)
def next_screen(self, *args):
self.current = "new_screen"
def back_screen(self, *args):
self.current = "main_screen"
class MyApp(App):
def build(self):
return MyScreenManager()
if __name__ == "__main__":
MyApp().run()
Upvotes: 1
Views: 180
Reputation: 1559
I tried no to change your code too much.
So parting from where you left first I used the button Accept
to initialize the label change in your next_scren
. With it we call a function start
passing the selected button list and the time, and use these two values to update the label.
For this update we can schedule a clock interval with another function to decide which is the next button.
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.stacklayout import StackLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.animation import Animation
from kivy.clock import Clock
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super(MyGrid, self).__init__(**kwargs)
self.sel_chords = []
self.time = 0
self.cols = 1
self.add_widget(Label(text="Please, select the chords you would like to practise."))
self.intro = StackLayout()
self.A = ToggleButton(text="A", size_hint=(.2, .2))
self.intro.add_widget(self.A)
self.E = ToggleButton(text="E", size_hint=(.2, .2))
self.intro.add_widget(self.E)
self.C = ToggleButton(text="C", size_hint=(.2, .2))
self.intro.add_widget(self.C)
self.D = ToggleButton(text="D", size_hint=(.2, .2))
self.intro.add_widget(self.D)
self.G = ToggleButton(text="G", size_hint=(.2, .2))
self.intro.add_widget(self.G)
self.Cadd9 = ToggleButton(text="Cadd9", size_hint=(.2, .2))
self.intro.add_widget(self.Cadd9)
self.add_widget(self.intro)
self.outro = GridLayout(cols=3)
self.outro.add_widget(Label(text="Seconds per chord:"))
self.minutes = TextInput(multiline=False)
self.outro.add_widget(self.minutes)
self.submit = Button(text="Accept", font_size=40)
self.submit.bind(on_press=self.pressed)
self.outro.add_widget(self.submit)
self.add_widget(self.outro)
def pressed(self, instance):
self.sel_chords =[]
if self.A.state == "down":
self.sel_chords.append("A")
if self.C.state == "down":
self.sel_chords.append("C")
if self.D.state == "down":
self.sel_chords.append("D")
if self.E.state == "down":
self.sel_chords.append("E")
if self.G.state == "down":
self.sel_chords.append("G")
if self.Cadd9.state == "down":
self.sel_chords.append("Cadd9")
try:
self.time = int(self.minutes.text) * 60
except:
self.time = 60
next_screen = App.get_running_app().root.get_screen("new_screen").children[0]
next_screen.start(self.sel_chords, self.time)
class MyGrid2(GridLayout):
def __init__(self, **kwargs):
super(MyGrid2, self).__init__(**kwargs)
self.cols = 1
self.rows = 2
self.temp = "A"
self.lbl = Label(text="A")
self.lbl.font_size = '300dp'
self.add_widget(self.lbl)
self.back = Button(text="Back", font_size=40)
self.add_widget(self.back)
self.selected_buttons = None
def start(self, button_list, time):
if len(button_list) == 0:
return
self.selected_buttons = button_list
self.lbl.text = self.selected_buttons[0]
Clock.schedule_interval(lambda x: self.update_lbl(self.next_button()), time)
def next_button(self):
if self.selected_buttons.index(self.lbl.text) == len(self.selected_buttons) - 1:
return 0
else:
return self.selected_buttons.index(self.lbl.text) + 1
def update_lbl(self, button, *kwargs):
self.lbl.text = self.selected_buttons[button]
class MyScreenManager(ScreenManager):
def __init__(self, **kwargs):
super(MyScreenManager, self).__init__(**kwargs)
self.main_screen = Screen(name="main_screen")
self.new_screen = Screen(name="new_screen")
self.add_widget(self.main_screen)
self.add_widget(self.new_screen)
main_grid = MyGrid()
main_grid.submit.bind(on_press=self.next_screen)
self.main_screen.add_widget(main_grid)
next_grid = MyGrid2()
next_grid.back.bind(on_press=self.back_screen)
self.new_screen.add_widget(next_grid)
def next_screen(self, *args):
self.current = "new_screen"
def back_screen(self, *args):
self.current = "main_screen"
class MyApp(App):
def build(self):
return MyScreenManager()
if __name__ == "__main__":
MyApp().run()
Now it's up to you to refine and change this code according to what you want.
Upvotes: 1