Python + Kivy (second screen is loading blank)
Clash Royale CLAN TAG#URR8PPP
Python + Kivy (second screen is loading blank)
I am learning kivy now... I am developing my 1st app for a friend, a very simple one. But I am facing this error:
Whenever I click "create account", the named 'Login(Screen)' loads blank. None of the widgets that I have created on my kivy file shows.
here are the codes:
==========================================================================
python file:
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
class Gerenciador(ScreenManager):
pass
class BoasVindas(Screen):
pass
class Login(Screen):
def logar(self, usuario, senha):
print("usuario=0, senha=1".format(usuario, senha))
class Resultado(Screen):
pass
class LoginApp(App):
def build(self):
return Gerenciador()
LoginApp().run()
========================================================================
kivy file:
<Gerenciador>:
BoasVindas:
name: 'boasvindas'
BoxLayout:
orientation:'vertical'
Label:
text:'Faça o seu Login ou crie uma nova conta'
Button:
text:'Login'
Button:
text:'Criar nova conta'
on_release:root.current='login'
Login:
name: 'login'
BoxLayout:
TextInput:
id:usuario
hint_text:'Usuário'
multiline: False
TextInput:
id:senha
hint_text:'Senha'
multiline: False
password: True
Button:
id:'btn'
text:'Ok'
on_press: self.parent.parent.logar(usuario.text, senha.text)
on_release:root.current='boasvindas'
=========================================================================
Any ideas on what I am missing? The first screen loads perfectly. If I swap the order, Login screen loads well. But the second screen is blank, no matter what content. as long as it is the second screen to load, it returns blank.
Thank you!
2 Answers
2
In your __init__()
method for Gerenciador
you are creating the Login
and BoasVindas
screens, but you are also crating them in your .kv
file. You should not do both. If you create them in the .kv
file, here is what your code can look like:
__init__()
Gerenciador
Login
BoasVindas
.kv
.kv
python file:
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
class Gerenciador(ScreenManager):
pass
class BoasVindas(Screen):
pass
class Login(Screen):
pass
class Resultado(Screen):
pass
class TesteLogin(App):
def build(self):
return Gerenciador()
TesteLogin().run()
kv file:
<Gerenciador>:
BoasVindas:
name: 'boasvindas'
BoxLayout:
orientation:'vertical'
Label:
text:'Faça o seu Login ou crie uma nova conta'
Button:
text:'Login'
Button:
text:'Criar nova conta'
on_release:root.current='login'
Login:
name: 'login'
BoxLayout:
TextInput:
id:usuario
hint_text:'Usuário'
multiline: False
TextInput:
id:senha
hint_text:'Senha'
multiline: False
password: True
Button:
id:'btn'
text:'Ok'
#on_press:self.parent.parent.logar(usuario.text, senha.text)
on_release:root.current='boasvindas'
In your .kv
file, when a class name is surrounded by <>
, that means that it is a template for building that class, but does not actually create the class. The classes without <>
are created, but the ones in your .kv
file are subordinate to the Gerenciador
class. So, when an instance of the Gerenciador
class is created (as in your App.build()
method), the Login
and BoasVindas
screens are created as its children. Note that I added the name
attribute to those screens in the .kv
file.
.kv
<>
<>
.kv
Gerenciador
Gerenciador
App.build()
Login
BoasVindas
name
.kv
Just to be sure, the name of your
.kv
file is testelogin.kv
, correct?– John Anderson
Aug 7 at 2:02
.kv
testelogin.kv
Problem - Second Screen Blank
There were four screens created. Two screens with children widgets and no screen names were created from the kv file. Another two screens with screen names but no children widgets were created from the Python code.
When the button, 'Criar nova conta'
was pressed to go to the screen with name, 'login'
it was using the instance that was created from the Python code which does not have any widgets in it i.e. it is blank.
'Criar nova conta'
'login'
Build/Processing Sequence
In Kivy App, the order of processing is as follow. To proof this, add print() and id()
functions into the kv file, and Python code, __init__()
method for each screen. It will show four different screens and memory location for each screen respectively.
id()
__init__()
class Gerenciador(ScreenManager):
def __init__(self):
super(Gerenciador, self).__init__()
print("nGerenciador.__init__():", id(self), "n")
self.add_widget(Login(name='login'))
self.add_widget(BoasVindas(name='boasvindas'))
class BoasVindas(Screen):
def __init__(self, **kwargs):
super(BoasVindas, self).__init__(**kwargs)
print("nBoasVindas.__init__():", id(self), "n")
class Login(Screen):
def __init__(self, **kwargs):
super(Login, self).__init__(**kwargs)
print("nLogin.__init__():", id(self), "n")
class TestLogin(App):
def build(self):
print("nTestLogin.build():")
return Gerenciador()
Button:
text:'Criar nova conta'
on_release:
print("self.parent.parent=", self.parent.parent)
print("id(self.parent.parent)=", id(self.parent.parent))
print("app.root.screen_names=", app.root.screen_names)
print("app.root.screens=", app.root.screens)
for x in app.root.screens: print("screen=0, id(screen)=1".format(x, id(x)))
root.current='login'
Solution
Please refer to the step-by-step solution and example for details.
__init__()
pass
name
name: 'boasvindas'
name: 'login'
self.parent.parent.logar(usuario.text, senha.text)
root.logar(usuario.text, senha.text)
Example
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
class Gerenciador(ScreenManager):
pass
class BoasVindas(Screen):
pass
class Login(Screen):
def logar(self, usuario, senha):
print("usuario=0, senha=1".format(usuario, senha))
class Resultado(Screen):
pass
class TesteLogin(App):
def build(self):
return Gerenciador()
TesteLogin().run()
#:kivy 1.11.0
<Gerenciador>:
BoasVindas:
name: 'boasvindas'
BoxLayout:
orientation:'vertical'
Label:
text:'Faça o seu Login ou crie uma nova conta' # Sign in or create a new account
Button:
text:'Login'
Button:
text:'Criar nova conta' # Create new account
on_release:root.current='login'
Login:
name: 'login'
BoxLayout:
TextInput:
id:usuario
hint_text:'Usuário' # User
multiline: False
TextInput:
id:senha
hint_text:'Senha' # Password
multiline: False
password: True
Button:
id:'btn'
text:'Ok'
on_press: self.parent.parent.logar(usuario.text, senha.text)
on_release:root.current='boasvindas' # Welcome
Output
I am ashamed to admit that my kivy file was named differently than "testelogin.kv". Everything worked just fine after I renamed the kivy file, except for the command "on_release: root.current..." It returns me an error saying that the root has no atrribute. I am grateful for all the help, but why can't I find anything within the "root", I would much appreciate. On time: when "root" is changed to "self.parent.parent..." it works flawlessly
– Cássio Rodrigo Peluso
Aug 8 at 17:45
Please update your post with the latest codes.
– ikolim
Aug 8 at 18:06
Code updated as requested. Also, is the exact same as suggest in the comments. Any idea why root."" is not referring to proper object? thank you!
– Cássio Rodrigo Peluso
Aug 12 at 6:04
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Thanks for the answer. The reason why I created the classes on the main file is that the line "name: 'login'" is not been recognized for some reason. when I tried to run the code you answered (with the names defined on kv file), it returns me an error " line 1065, in get_screen raise ScreenManagerException('No Screen with name "%s".' % name) kivy.uix.screenmanager.ScreenManagerException: No Screen with name "login"." I appreciate any further help. Thank you!
– Cássio Rodrigo Peluso
Aug 6 at 20:39