Why does Kivy ScreenManager not recognize my screen in Kivy? - python

This is my first time asking a question, and a beginner to Python and Kivy.
While running a program using Kivy, I developed some screens which operated as planned. However, when adding a new screen, it was not recognized and this error was returned.
File "kivy_event.pyx", line 1154, in kivy._event.EventObservers._dispatch
File "C:\Users\MyName\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\uix\screenmanager.py", line 1045, in on_current
screen = self.get_screen(value)
File "C:\Users\MyName\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\uix\screenmanager.py", line 1071, in get_screen
raise ScreenManagerException('No Screen with name "%s".' % name)
kivy.uix.screenmanager.ScreenManagerException: No Screen with name "sign_up_screen_success".
Here is my main.py code:
import os
os.chdir(r"C:\Users\MyName\Documents\mobile app")
from kivy.app import App
import json
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from datetime import datetime
Builder.load_file('design.kv')
class LoginScreen(Screen):
def sign_up(self):
self.manager.current = "sign_up_screen"
class RootWidget(ScreenManager):
pass
class SignUpScreen(Screen):
def add_user(self, uname, pword):
with open("users.json") as file:
users = json.load(file)
users[uname] = {'username': uname, 'password': pword,
'created': datetime.now().strftime("%Y-%m-%d %H-%M-%S")}
with open("users.json", 'w') as file:
json.dump(users, file)
self.manager.current = "sign_up_screen_success"
class SignUpScreenSuccess(Screen):
pass
class MainApp(App):
def build(self):
return RootWidget()
if __name__ == "__main__":
MainApp().run()
And here is my .kv code:
<LoginScreen>:
GridLayout:
cols: 1
GridLayout:
cols: 1
Label:
text: "User Login"
TextInput:
hint_text: "Username"
TextInput:
hint_text: "Password"
Button:
text: "Login"
GridLayout:
cols: 2
Button:
text: "Forgot Password?"
Button:
text: "Sign Up"
on_press: root.sign_up()
<SignUpScreen>:
GridLayout:
cols: 1
Label:
text: "Sign up for a space journey!"
TextInput:
id: username
hint_text: "Username"
TextInput:
id: password
hint_text: "Password"
Button:
text: "Submit"
on_press: root.add_user(root.ids.username.text, root.ids.password.text)
<SignUpScreenSuccess>:
GridLayout:
cols: 1
Label:
text: "Sign up successful!"
Button:
text: "Login page"
<RootWidget>:
LoginScreen:
name: "login_screen"
SignUpScreen:
name: "sign_up_screen"
SignUpScreenSuccess:
name: "sign_up_screen_success"
From what I gathered, since I defined "sign_up_screen_success" to correspond with SignUpScreenSuccess in the RootWidget of my .kv code, I should proceed to a different screen. So, why is this not working?
SignUpScreen and LoginScreen worked fine, but I could not see any difference in code between those and SignUpScreenSuccess.
If I need to clarify anything else, let me know.
Thanks.

Im not sure that it solves the problem, but in examples I've seen and according to the documentation:
https://kivy.org/doc/stable/guide/lang.html
The root widget in the kv doesn't have the <> brackets.
like so:
RootWidget:
LoginScreen:
name: "login_screen"
SignUpScreen:
name: "sign_up_screen"
SignUpScreenSuccess:
name: "sign_up_screen_success"

Hey I've been working on Kivy aswell the last weeks. Could you try initialising the names like this:
<LoginScreen>:
name: "login_screen"
GridLayout:
cols: 1
GridLayout:
cols: 1
Label:
text: "User Login"
TextInput:
hint_text: "Username"
TextInput:
hint_text: "Password"
Button:
text: "Login"
GridLayout:
cols: 2
Button:
text: "Forgot Password?"
Button:
text: "Sign Up"
on_press: root.sign_up()
<SignUpScreen>:
name: "sign_up_screen"
GridLayout:
cols: 1
Label:
text: "Sign up for a space journey!"
TextInput:
id: username
hint_text: "Username"
TextInput:
id: password
hint_text: "Password"
Button:
text: "Submit"
on_press: root.add_user(root.ids.username.text, root.ids.password.text)
<SignUpScreenSuccess>:
name: "sign_up_screen_success"
GridLayout:
cols: 1
Label:
text: "Sign up successful!"
Button:
text: "Login page"
<RootWidget>:
LoginScreen:
SignUpScreen:
SignUpScreenSuccess:
I coded my screens like this, this should work I think

Related

Kivy Taking user input from textinput and setting the text as a label

I have seen plenty of very similar questions asked, and none of the answers seem to work. I stripped a program to it's very basics and it still doesn't seem to work, here's the code:
.kv file
WindowManager:
FirstWindow:
SecondWindow:
<FirstWindow>:
name: 'first'
GridLayout:
cols: 1
size: root.size
GridLayout:
cols: 2
Label:
text: 'Put some text'
TextInput:
id: item
Button:
on_release: app.root.current = 'second'
<SecondWindow>:
name: 'second'
BoxLayout:
orientation: 'vertical'
Label:
id: bi
text: root.manager.get_screen('first').ids.item.text
The .py file is very basic, no extra info that could conflict the program. So when I enter text into the label, it returns an empty string on the Second Screen. Can anyone help?
Your screen manager looks unfamiliar with me, try this:
main.kv
<RootWidget>:
manager: manager
ScreenManager:
id: manager
pos_hint: {'top': 0.9}
Screen:
name: 'Screen 1'
TextInput:
id: input1
text: 'Type Here'
size_hint: 0.2,0.1
pos_hint: {'center_x':0.5,'center_y':0.6}
Button:
text: 'Move to screen 2'
size_hint: 0.2,0.1
pos_hint: {'center_x':0.5,'center_y':0.4}
on_release: app.tmb1()
Screen:
name: 'Screen 2'
TextInput:
id: input2
text: 'Screen 2'
size_hint: 0.2,0.1
pos_hint: {'center_x':0.5,'center_y':0.6}
Button:
text: 'Move to screen 1'
size_hint: 0.2,0.1
pos_hint: {'center_x':0.5,'center_y':0.4}
on_release: app.tmb2()
main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import NumericProperty, ObjectProperty
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
class RootWidget(FloatLayout):
manager = ObjectProperty()
class MainApp(App):
def build(self):
return RootWidget()
def tmb1(self):
self.root.ids['input2'].text=self.root.ids['input1'].text
self.root.manager.current='Screen 2'
def tmb2(self):
self.root.ids['input1'].text=self.root.ids['input2'].text
self.root.manager.current='Screen 1'
if __name__ == '__main__':
MainApp().run()

Python Kivy TextInput not working?

I have created a simple login and registration screen using kivy, but the TextInput do not let me type inside of it? This error is occuring on both the LoginScreen and the RegistrationScreen. I tried looking up past questions on here, but i couldn't find anything.
The Python file:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class Login_Screen(Screen):
def login(self):
if self.ids.username.text == "root" and\
self.ids.passwrd.text == "123":
print("Direct Entry")
self.manager.current = "Login_Successful"
else:
print("Wrong Password")
self.manager.current = "Login_Failed"
def registration(self):
self.manager.current = "Registration_Screen"
class LoginConfirmationScreen(Screen):
pass
class Registration_Screen(Screen):
def MainScreen(self):
self.manager.current = "Login_Screen"
class Login_Failed(Screen):
def MainScreen(self):
self.manager.current = "Login_Screen"
class RootWidget(ScreenManager):
pass
Builder.load_file("MainApp.kv")
class MainApp(App):
def build(self):
return RootWidget()
if __name__ == "__main__":
MainApp().run()
And the MainApp.kv file:
<RootWidget>:
id: Main
Login_Screen:
id: login
name: "Login_Screen"
Login_Failed:
id: Failed
name: "Login_Failed"
Registration_Screen:
id: register
name: 'Registration_Screen'
<Login_Screen>:
GridLayout:
rows:3
cols:2
Label:
text: "Username:"
font_size: 20
TextInput:
id: username
multiline: False
hint_text: 'Enter your Username'
Label:
text: "Password"
font_size: 20
TextInput:
id: passwrd
multiline: False
hint_text: 'Enter your Password'
password: True
Button:
text: "Register"
on_press: root.registration()
Button:
text: "Sign In"
on_press: root.login()
<Registration_Screen>:
GridLayout:
rows:3
cols:2
Label:
text: 'First Name:'
font_size: 20
TextInput:
id: FirstName
multiline: False
hint_text: 'Enter your First Name'
Label:
text: 'Surname'
font_size: 20
TextInput:
id: Surname
multiline: False
hint_text: 'Enter your Surname'
Button:
text: "Create Account"
on_press: root.MainScreen()
<Login_Failed>:
BoxLayout:
orientation: "vertical"
Label:
text: "Login Failed"
Button:
text: "Try again"
on_press: root.MainScreen()
Thanks for help :)
Remove this:
Builder.load_file("MainApp.kv")
from your py file because you're App instance, ie:
class MainApp(App):
Loads it automatically already.

Button to print the the Text Input is not working

The whole code is working well. But when u go to:
student > Add New student > > Fill all columns of new student > then submit
it's not working and I can't figure out the issue. Here is the following code. Any help will be appreciated
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen ,FadeTransition
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
import csv
from kivy.uix.textinput import TextInput
Builder.load_string("""
<MenuScreen>:
BoxLayout:
Button:
text: 'Teacher'
on_press: root.manager.current = 'screen1'
Button:
text: 'Student '
on_press:root.manager.current = 'screen2'
Button:
text: 'Quit'
<Screen1>:
BoxLayout:
Button:
text: 'Teacher Info'
#on_press:root.manager.current = 'login'
Button:
text: 'Teacher Attandance'
Button:
text: 'Add New Teacher'
on_press:root.manager.current = 'add_teacher'
Button:
text: 'Back'
on_press:root.manager.current ='menu'
<add_new_teacher>:
GridLayout:
cols:2
Label:
text:'Name'
TextInput:
id: name_input
multiline: False
Label:
text:'Father Name'
TextInput:
id: name_input
multiline: False
Label:
text: 'Mother Name'
TextInput:
id: name_input
multiline: False
Label:
text: 'Class'
TextInput:
id: name_input
multine: False
Label:
text:'Roll no.'
text: 'Student Info'
on_press:root.csv_std()
Button:
text: 'Student Attandance'
# on_press:root.manager.current ='login'
Button:
text: 'Add New Student'
on_press:root.manager.current = 'add_student'
Button
text: 'Back'
on_press:root.manager.current = 'menu'
<add_new_student>:
GridLayout:
cols:2
Label:
text:'Name'
TextInput:
id: self.name
multiline: False
Label:
text:'Father Name'
TextInput:
id: self.fname
multiline: False
Label:
text: 'Mother Name'
TextInput:
id: self.mname
multiline: False
Label:
text: 'Class'
TextInput:
id: self.c
multine: False
Label:
text:'Roll no.'
TextInput:
id: self.r
multiline:False
Button:
text:'Print'
Button:
text:'Submit'
on_press:root.print_text()
Button:
text:'Back'
on_press:root.manager.current= 'screen2'
""")
# Declare both screens
class MenuScreen(Screen):
pass
class add_new_teacher(Screen):
pass
class Screen1(Screen):
pass
class Screen2(Screen):
def csv_std(self):
f = open("a.csv", 'r')
reader = csv.reader(f)
for row in reader:
print(" ".join(row))
pass
class add_new_student(Screen):
def print_text(self):
for child in reversed(self.children):
if isinstance(child, TextInput):
print child.text
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(add_new_teacher(name='add_teacher'))
sm.add_widget(add_new_student(name='add_student'))
sm.add_widget(Screen1(name='screen1'))
sm.add_widget(Screen2(name='screen2'))
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
You code formatting was horrible, but at least you didn't use backticks. For future cases, copy&paste your whole example you want to show here, then select that example(whole) and press Ctrl + K, which will indent all selected lines, so that it'd look ok.
The code works exactly how it supposed to work, because root.print_text() targets add_new_student class and its children - not GridLayout which you want to access.
Edit the line with for to this: for child in reversed(self.children[0].children): and you are good to go. :)
Or more efficient solution would be to get that Screen to behave as a layout too, which you can get with inheritting both from Screen and some layout, but ensure the layout is first:
class add_new_student(GridLayout, Screen):
def print_text(self):
for child in reversed(self.children):
if isinstance(child, TextInput):
print child.text
kv:
<add_new_student>:
cols:2
Label:
text:'Name'

Passing information between classes in Kivy

I have a basic app in Kivy with a class for each screen. I would like to have the user enter some text in one screen and for this to be displayed in a label on another screen.
I've been through all the similar posts but can't seem to get anything working.
The two classes EnterSentences and Review have ObjectProperties. Is there a way to connect these with bind? Or do I need to just structure things completely differently?
Any help much appreciated. Here's the .py file
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
class MainMenu(BoxLayout):
def enter_sentences_button(self):
self.clear_widgets()
self.add_widget(EnterSentences())
def review_button(self):
self.clear_widgets()
self.add_widget(Review())
def settings_button(self):
pass
class EnterSentences(BoxLayout):
search_box = ObjectProperty()
def main_menu(self):
self.clear_widgets()
self.add_widget(MainMenu())
class Review(BoxLayout):
sentence = ObjectProperty()
class NewApp(App):
pass
if __name__ == "__main__":
NewApp().run()
and the .kv file:
MainMenu
<MainMenu>:
orientation: 'vertical'
Label:
text: "Welcome to your Flash Card App!"
size_hint_y: 5
BoxLayout:
size_hint_y: 1
orientation: "horizontal"
Button:
text: "Enter sentences"
on_press: root.enter_sentences_button()
Button:
text: "Review"
on_press: root.review_button()
Button:
text: "Settings"
<EnterSentences>:
search_box: enter_sentence
orientation: "vertical"
Label:
text: "Enter your sentences here:"
size_hint_y: 4
TextInput:
id: enter_sentence
TextInput:
TextInput:
BoxLayout:
orientation: 'horizontal'
Button:
text: 'Main Menu'
on_press: root.main_menu()
Label:
text: ''
<Review>:
orientation: 'vertical'
Label:
size_hint_y: 4
text: root.search_box
TextInput:
size_hint_y: 1
You only have to change the kv file. You could add the text from the 3 TextInputs to 3 variables readable from the whole app:
TextInput:
+ on_text: app.sentence1=self.text
id: enter_sentence
TextInput:
+ on_text: app.sentence2=self.text
TextInput:
+ on_text: app.sentence3=self.text
Then you could access the new variables in the Review:
<Review>:
orientation: 'vertical'
Label:
size_hint_y: 4
text: app.sentence1 + "\n" + app.sentence2 + "\n" + app.sentence3
TextInput:
size_hint_y: 1

Invalid data after declaration in Kivy

I don't understand why I have this type of error when I run my code. I've checked this several times and everything seems to be good, still the code does not want to run.
Here's my __main__.py file :
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.properties import ObjectProperty # at top of file
class AccountDetailsForm(AnchorLayout):
server_box = ObjectProperty()
username_box = ObjectProperty()
password_box = ObjectProperty()
def login(self):
print(self.server_box.text)
print(self.username_box.text)
print(self.password_box.text)
class Orkiv(App):
pass
Orkiv().run()
And here's my orkiv.kv file :
AccountDetailsForm:
<AccountDetailsForm>:
anchor_y: "top"
server_box: server_input
username_box: username_input
password_box: password_input
BoxLayout:
orientation: "vertical"
height: "200dp"
size_hint_y: None
GridLayout:
cols: 2
row_default_height: "40dp"
row_force_default: True
spacing: "10dp"
padding: "10dp"
Label:
text: "Server" //THE ERROR SEEMS TO HAPPEN HERE
AccountDetailsTextInput:
id: server_input
Label:
text: "Username"
AccountDetailsTextInput:
id: username_input
Label:
text: "Password"
AccountDetailsTextInput:
password: True
id: password_input
Button:
size_hint_y: None
height: "40dp"
text: "Login"
on_press: root.login()
Any ideas ? Thanks.
In your orkiv.kv file, change AccountDetailsTextInput to just TextInput.
AccountDetailsForm:
<AccountDetailsForm>:
anchor_y: "top"
server_box: server_input
username_box: username_input
password_box: password_input
BoxLayout:
orientation: "vertical"
height: "200dp"
size_hint_y: None
GridLayout:
cols: 2
row_default_height: "40dp"
row_force_default: True
spacing: "10dp"
padding: "10dp"
Label:
text: "Server"
TextInput:
id: server_input
Label:
text: "Username"
TextInput:
id: username_input
Label:
text: "Password"
TextInput:
password: True
id: password_input
Button:
size_hint_y: None
height: "40dp"
text: "Login"
on_press: root.login()
The app should run. See my output below.
Let us know if this helps.
According to kivy module documentation, if you want to provide a box for editable plain text use the class "TextInput". There is no class by the name "AccountDetailsTextInput".

Categories