Reputation: 25
I am experimenting with kivy by developing an app to register exercise routines, with a few screens in a screenmanager. However, when running the code, I am getting an ScreenManagerException:
kivy.uix.screenmanager.ScreenManagerException: No Screen with name "('Suplementos', <kivy.uix.button.Button object at 0xb3d3341c>)".
The app is currently made of the following pieces of code (python 2.7 + kivy 1.9):
main.py
#coding:utf-8
from functools import partial
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.scrollview import ScrollView
import time
class TelaInicial(Screen):
layout_telainicial = ObjectProperty(None)
def __init__(self, **kwargs):
super(TelaInicial, self).__init__(**kwargs)
opcoes = [
'Suplementos',
'Cardiovascular',
'Novo treino'
]
for opt in opcoes:
Opcao = Button(
text=str(opt),
size_hint_y=None,
height=60,
)
Opcao.bind(on_press=partial(self.ir_para, opt))
self.ids.layout_telainicial.add_widget(Opcao)
def ir_para(self, *args):
self.parent.current = str(args)
class Suplementos(Screen):
layout_suplementos = ObjectProperty(None)
def __init__(self, **kwargs):
hora = time.asctime()
super(Suplementos, self).__init__(**kwargs)
mostrar_hora = Label(text=str(hora))
self.ids.layout_suplementos.add_widget(mostrar_hora)
class Cardiovascular(Screen):
layout_cardiovascular = ObjectProperty(None)
def __init__(self, **kwargs):
hora = time.asctime()
super(Cardiovascular, self).__init__(**kwargs)
mostrar_hora = Label(text=str(hora))
self.ids.layout_cardiovascular.add_widget(mostrar_hora)
class NovoTreino(Screen):
layout_novotreino = ObjectProperty(None)
def __init__(self, **kwargs):
super(NovoTreino, self).__init__(**kwargs)
AdicionarExercicio = Button(
text='+',
size_hint_y=None,
height=60,
)
AdicionarExercicio.bind(on_press=lambda a: self.NovoExercicio)
self.ids.layout_novotreino.add_widget(AdicionarExercicio)
def NovoExercicio(self, *args):
self.parent.current = 'Seleção de exercícios'
class SelecaoExercicio(Screen):
pass
class GerenciadorApp(App):
def build(self):
MyScreenManager = ScreenManager()
MyScreenManager.add_widget(TelaInicial())
MyScreenManager.add_widget(Suplementos())
MyScreenManager.add_widget(Cardiovascular())
MyScreenManager.add_widget(NovoTreino())
MyScreenManager.add_widget(SelecaoExercicio())
return MyScreenManager
GerenciadorApp().run()
gerenciador.kv
<TelaInicial>
name: 'Tela inicial'
ScrollView:
GridLayout:
id: layout_telainicial
cols: 1
padding: 10
spacing: 10
size_hint: 1, None
height: self.minimum_height
<Suplementos>
name: 'Suplementos'
ScrollView:
GridLayout:
id: layout_suplementos
cols: 1
padding: 10
spacing: 10
size_hint: 1, None
height: self.minimum_height
Label:
text: 'Registro de suplementos'
<Cardiovascular>
name: 'Cardiovascular'
ScrollView:
GridLayout:
id: layout_cardiovascular
cols: 1
padding: 10
spacing: 10
size_hint: 1, None
height: self.minimum_height
Label:
text: 'Exercício cardiovascular'
<NovoTreino>
name: 'Novo treino'
ScrollView:
GridLayout:
id: layout_novotreino
cols: 1
padding: 10
spacing: 10
size_hint: 1, None
height: self.minimum_height
Label:
text: 'Treino de musculação'
<SelecaoExercicio>
name: 'Seleção de exercícios'
ScrollView:
GridLayout:
id: layout_selecaoexercicios
cols: 1
padding: 10
spacing: 10
size_hint: 1, None
height: self.minimum_height
In a former version of the code, I also tried a lambda function instead of the partial() fuction, used within the TelaInicial class constructor to bind the "on_press" buttons' properties:
class TelaInicial(Screen):
layout_telainicial = ObjectProperty(None)
def __init__(self, **kwargs):
super(TelaInicial, self).__init__(**kwargs)
opcoes = [
'Suplementos',
'Cardiovascular',
'Novo treino'
]
for opt in opcoes:
Opcao = Button(
text=str(opt),
size_hint_y=None,
height=60,
)
Opcao.bind(on_press=self.ir_para(opt))
self.ids.layout_telainicial.add_widget(Opcao)
def ir_para(self, destino, *args):
self.parent.current = str(destino)
This would return always the last screen in the list of options, 'NovoTreino', for all buttons, instead of the screen identified by each button.
Why isn't the code working in each of these cases - and how could I fix it?
Upvotes: 1
Views: 1141
Reputation: 5405
The problem is that you set the screenmanagers current to the whole list of args, when you only want the first item of args.
>>> print(args)
('Suplementos', <kivy.uix.button.Button object at 0xb3d3341c>)
>>> print(args[0])
'Suplementos'
So what you need is:
def ir_para(self, *args):
self.parent.current = str(args[0])
Upvotes: 1