I'm quite new to Kivy and have been repeatedly having issues with displaying things. I am building a basic app to track students, assign them to school houses (like in Harry Potter) and display them. I created a "for" loop to add users to labels in a stack layout which would then display them in a scroll view, but for some reason, when I run the file, nothing is displayed. I have no idea what is going on. Please run the file yourself, to troubleshoot the problem
Note: The problem concerns lines 261-280 in the python file
Python file:
from os.path import join
from random import random, choice
from kivy.app import App
from kivy.config import Config
Config.set('graphics', 'width', '400')
Config.set('graphics', 'height', '600')
from kivy.storage.jsonstore import JsonStore
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.checkbox import CheckBox
from kivy.uix.popup import Popup
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.stacklayout import StackLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.dropdown import DropDown
from kivy.metrics import dp
from kivy.properties import ObjectProperty, StringProperty, BooleanProperty, Clock
from kivy.graphics.vertex_instructions import Line, Rectangle, Ellipse
from kivy.graphics.context_instructions import Color
from kivy.core.window import Window
class LoginScreen(Screen): #This screen is the first window displayed when the program runs
developer_version = StringProperty('1.0.0') #Incriment with each software update/patch. Patch ex.: 1.0.1 and Update ex.: 1.1.0
email = ObjectProperty(None) #Email variable which will recieve text data from Kivy
password = ObjectProperty(None) #Password variable which will recieve text data from Kivy
id_credentials = None #A variabled used to identify which password file the user has sign in through
id_name = {} #A dict used to assign the user an id based off which password file they sign in through
remember_login_user = None #A (to be) boolean used to determine whether the user wants to remember their login data
user_found_line = None #Identifies what line the user's data appeared in their respective password file
specific_house = '' #A stringed int for which house the user has selected
check_box_cond = ObjectProperty(None) #Checks whether the "remeber login" checkbox is active
index_count = 0 #Keeps track of what line login credentials are on
cred_name = '' #Stores the user's login data that is within the ..._user dict
passwordStudents = open('passwords/passwordStudents.txt', 'r') #40-43 all read the login text files used to check if login credentials are correct
passwordTeachers = open('passwords/passwordTeachers.txt', 'r')
passwordAdmin = open('passwords/passwordAdmin.txt', 'r')
#student_char_creds = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '@', '.'] <--- Likely won't need this
student_user = {}
teacher_user = {}
admin_user = {}
for i in passwordStudents:
first, last, email, password = i.strip().split(';')
student_user[f'{first} {last}'] = (email, password)
for i in passwordTeachers:
first, last, email, password = i.strip().split(';')
teacher_user[f'{first} {last}'] = (email, password)
for i in passwordAdmin:
first, last, email, password = i.strip().split(';')
admin_user[f'{first} {last}'] = (email, password)
passwordStudents.close()
passwordTeachers.close()
passwordAdmin.close()
def loginBtn(self): #Checks eamil and password to assess whether user credentials are correct and if said user is a student, teacher, or admin
login_email = self.email.text
login_password = self.password.text
login_lst = self.email.text + ', ' + self.password.text
su = False
tu = False
au = False
for i in self.student_user.values():
if login_email in i:
self.cred_name = i
if i[0] + ', ' + i[1] == login_lst:
su = True
login_lst = ''
self.id_credentials = 'Student'
self.user_cred(self.student_user)
self.reset()
self.home()
else:
su = True
self.reset()
self.login_error()
self.index_count += 1
for i in self.teacher_user.values():
if login_email in i:
self.cred_name = i
if i[0] + ', ' + i[1] == login_lst:
tu = True
login_lst = ''
self.id_credentials = 'Teacher'
self.user_cred(self.teacher_user)
self.reset()
self.home()
else:
tu = True
self.reset()
self.login_error()
self.index_count += 1
for i in self.admin_user.values():
if login_email in i:
self.cred_name = i
if i[0] + ', ' + i[1] == login_lst:
au = True
login_lst = ''
self.id_credentials = 'Admin'
self.user_cred(self.admin_user)
self.reset()
self.home()
else:
au = True
self.reset()
self.login_error()
self.index_count += 1
if su == False:
if tu == False:
if au == False:
self.reset()
self.login_error()
def reset(self): #Resets textinputs in login
self.email.text = ''
self.password.text = ''
def home(self): #Redirects user to home window
sm.transition.direction = 'up'
sm.current = 'home'
def login_error(self): #Handles login errors
buttons = Button(text='Got It')
labels = Label(text='Invalid username or password \n\n')
grids = GridLayout(rows=2)
grids.add_widget(labels)
grids.add_widget(buttons)
pop = Popup(title='Invalid Login',
content=grids,
size_hint=(None, None), size=(450, 450),
auto_dismiss=False)
buttons.bind(on_press=pop.dismiss)
pop.open()
def user_cred(self, cred): #Gives user an id
key_lst = list(cred.keys())
val_lst = list(cred.values())
pos = val_lst.index(self.cred_name)
self.id_name[key_lst[pos]] = self.id_credentials
def remember_login(self): #Allows users to remeber their login data for the next time they login
'''
a = list(str(open(f'passwords/password{self.id_credentials}.txt').readlines(self.user_found_line)))
for i in range(2):
a.pop(0)
a.pop(-1)
for i in range(2):
a.pop(-1)
b = ''.join(a)
c = b.split(' ')
remember_dir_file = c[-1]
if remember_dir_file == 'True':
self.email.text =
'''
pass
def check_if_box_active(self): #Allows users to access app without needing to sign in every time
pass
class HomeScreen(Screen): #The main page that the user is directed to
def return_to_login_Btn(self):
sm.transition.direction = 'down'
sm.current = 'login'
LoginScreen().id_name.clear()
def check_user_id_1(self):
if list(LoginScreen().id_name.values())[0] == 'Student':
StudentsGridList().foo('1')
sm.transition.direction = 'left'
sm.current = 'studentHome'
elif list(LoginScreen().id_name.values())[0] == 'Teacher':
StudentsGridList().foo('1')
sm.transition.direction = 'left'
sm.current = 'teacherHome'
elif list(LoginScreen().id_name.values())[0] == 'Admin':
StudentsGridList().foo('1')
sm.transition.direction = 'left'
sm.current = 'adminHome'
def check_user_id_2(self):
if list(LoginScreen().id_name.values())[0] == 'Student':
StudentsGridList().foo('2')
sm.transition.direction = 'left'
sm.current = 'studentHome'
elif list(LoginScreen().id_name.values())[0] == 'Teacher':
StudentsGridList().foo('2')
sm.transition.direction = 'left'
sm.current = 'teacherHome'
elif list(LoginScreen().id_name.values())[0] == 'Admin':
StudentsGridList().foo('2')
sm.transition.direction = 'left'
sm.current = 'adminHome'
def check_user_id_3(self):
if list(LoginScreen().id_name.values())[0] == 'Student':
StudentsGridList().foo('3')
sm.transition.direction = 'left'
sm.current = 'studentHome'
elif list(LoginScreen().id_name.values())[0] == 'Teacher':
StudentsGridList().foo('3')
sm.transition.direction = 'left'
sm.current = 'teacherHome'
elif list(LoginScreen().id_name.values())[0] == 'Admin':
StudentsGridList().foo('3')
sm.transition.direction = 'left'
sm.current = 'adminHome'
def check_user_id_4(self):
if list(LoginScreen().id_name.values())[0] == 'Student':
StudentsGridList().foo('4')
sm.transition.direction = 'left'
sm.current = 'studentHome'
elif list(LoginScreen().id_name.values())[0] == 'Teacher':
StudentsGridList().foo('4')
sm.transition.direction = 'left'
sm.current = 'teacherHome'
elif list(LoginScreen().id_name.values())[0] == 'Admin':
StudentsGridList().foo('4')
sm.transition.direction = 'left'
sm.current = 'adminHome'
def foobar(self):
sm.current = 'spec'
class StudentSpecificHomeScreen(Screen): #Students can access their students' house pages
def return_to_home_Btn(self):
sm.transition.direction = 'right'
sm.current = 'home'
class TeacherSpecificHomeScreen(Screen): #Teachers can access their teachers' house pages
def return_to_home_Btn(self):
sm.transition.direction = 'right'
sm.current = 'home'
class AdminSpecificHomeScreen(Screen): #Admin can access their admins' house pages
def return_to_home_Btn(self):
sm.transition.direction = 'right'
sm.current = 'home'
class StudentsGridList(StackLayout): #Lists and orders students into a StackLayout
def foo(self, specific_house):
print(specific_house)
if int(specific_house) == int:
house_users = open(f'houses/house{specific_house}.txt', 'r')
for user in house_users:
user = user.split('\n')[0]
if user == 'Griffin Neal':
user = f'[color=#000000][b]Dev:[/b] [color=#028A0F][i]{user}[/i]'
else:
user = f'[color=#000000]{user}'
size = dp(150)
labels = Label(text=user, size_hint=(None,None), size=(size, size), bold=True, markup=True)
self.add_widget(labels)
house_users.close()
else:
pass
class StudentsList(ScrollView): #Lists all students in a scroll view
pass
def SortingHat(): #Admins can use this to randomly sort students into houses
pass
class WindowManager(ScreenManager):
pass
sm = WindowManager()
class MyApp(App):
def build(self):
screens = [LoginScreen(name='login'),
HomeScreen(name='home'),
StudentSpecificHomeScreen(name='studentHome'),
TeacherSpecificHomeScreen(name='teacherHome'),
AdminSpecificHomeScreen(name='adminHome')]
for screen in screens:
sm.add_widget(screen)
sm.current = 'login'
Window.clearcolor = (230/255,230/255,230/255,1)
return sm
if __name__ == '__main__':
MyApp().run()
Kivy file:
LoginScreen:
<LoginScreen>:
name: "login"
email: email
password: psswrd
check_box_cond: checks
BoxLayout:
orientation: "vertical"
canvas.before:
Color:
rgba: 1,1,1,1
Label:
text: "Login"
pos: 0, root.height/3
font_size: 100
color: 50/255,50/255,50/255,1
GridLayout:
cols: 2
Label:
size_hint: None, None
width: "175dp"
height: "50dp"
text: "Email:"
font_size: 50
color: 50/255,50/255,50/255,1
TextInput:
id: email
multiline: False
size_hint: None, None
width: "200dp"
height: "50dp"
font_size: (root.width**2 + root.height**2) / 14**4
GridLayout:
cols: 2
Label:
size_hint: None, None
width: "175dp"
height: "50dp"
text: "Password:"
font_size: 50
color: 50/255,50/255,50/255,1
TextInput:
id: psswrd
multiline: False
size_hint: None, None
width: "200dp"
height: "50dp"
password: True
font_size: (root.width**2 + root.height**2) / 14**4
GridLayout:
cols: 3
row_force_default: True
row_default_height: "40"
Label:
text: ""
size_hint_x: None
width: "100dp"
CheckBox:
id: checks
color: 0,0,0,1
size_hint_x: None
width: "40dp"
on_active:
root.remember_login()
Label:
font_size: (root.width**2 + root.height**2) / 14**4 - 20
text: "Remeber sign in?"
color: 50/255,50/255,50/255,1
size_hint_x: None
width: "160dp"
FloatLayout:
Button:
background_color: 1,1,1,1
size_hint: None, None
width: "150dp"
height: "100dp"
pos: root.width/2 - 150, root.height/4 - 250
text: "Submit"
font_size: (root.width**2 + root.height**2) / 14**4
color: 10/255,10/255,10/255,1
on_release:
root.loginBtn()
Label:
size_hint: None, None
width: "150dp"
height: "100dp"
pos: root.width/2 - 150, root.height/4 - 375
color: 10/255, 10/255, 10/255, 1
text: f"Version: {root.developer_version}"
<HomeScreen>:
name: "home"
GridLayout:
rows: 3
BoxLayout:
size_hint: 1, 0.15
Label:
text: ""
Button:
size_hint: 0.4, 1
text: "Logout"
font_size: (root.width**2 + root.height**2) / 14**4
on_release:
root.return_to_login_Btn()
GridLayout:
cols: 2
rows: 2
Button:
text: "House 1"
font_size: (root.width**2 + root.height**2) / 14**4
on_release:
root.check_user_id_1()
Button:
text: "House 2"
font_size: (root.width**2 + root.height**2) / 14**4
on_release:
root.check_user_id_2()
Button:
text: "House 3"
font_size: (root.width**2 + root.height**2) / 14**4
on_release:
root.check_user_id_3()
Button:
text: "House 4"
font_size: (root.width**2 + root.height**2) / 14**4
on_release:
root.foobar()
<StudentSpecificHomeScreen>:
GridLayout:
rows: 2
name: "studentHome"
FloatLayout:
size_hint: 1, None
height: root.height/6
Button:
pos: root.width/2 - root.width/4, root.height*3/4 + 85
size_hint: None, None
width: root.width/2
height: "100dp"
text: "Return Home"
font_size: (root.width**2 + root.height**2) / 14**4
on_release:
root.return_to_home_Btn()
StudentsList:
StudentsGridList:
padding: ('20dp', '20dp', '20dp', '20dp')
spacing: ('20dp', '20dp')
size_hint: 1, None
height: self.minimum_height
<TeacherSpecificHomeScreen>:
name: "teacherHome"
GridLayout:
rows: 2
Button:
size_hint: None, None
width: "175dp"
height: "100dp"
text: "Return Home"
font_size: (root.width**2 + root.height**2) / 14**4
on_release:
root.return_to_home_Btn()
<AdminSpecificHomeScreen>:
name: "adminHome"
GridLayout:
rows: 2
Button:
size_hint: None, None
width: "175dp"
height: "100dp"
text: "Return Home"
font_size: (root.width**2 + root.height**2) / 14**4
on_release:
root.return_to_home_Btn()
Fake student credentials text file (put it into a text file called "passwordStudents.txt" in a folder called "passwords"):
Griffin;Neal;[email protected];1234
Ela;Talor;[email protected];4321
Lucas;Dore;[email protected];0987
Matilde;Obrien;[email protected];7890
Mia;McCabian;[email protected];9078
Eli;Cobbb;[email protected];6785
James;May;[email protected];4132
Connor;McCarren;[email protected];1626
Gabe;Newell;[email protected];0000
Student houses (create four text files with the students' first and last names at random called "house1.txt", "house2.txt", etc. in a folder called "houses")
A couple problems with your code:
StudentsGridList().foo('4')
, you are creating a new instance of StudentsGridList
and calling the foo()
method of that new instance. Doing so will have no effect on the StudentsGridList
instance that is in the StudentSpecificHomeScreen
of your GUI.if
statement if int(specific_house) == int:
in your foo()
method will always be False
, since your are comparing an integer to a built-in method.To correct the first problem, you will probably need to use the get_screen() method of ScreenManager
along with some ids
in order to access the instance of StudentsGridList
that is actually in your GUI. You will probably need to assign an id
to the StudentsGridList
. This can be done in your kv
file:
StudentsList:
StudentsGridList:
id: sgl # added id
padding: ('20dp', '20dp', '20dp', '20dp')
spacing: ('20dp', '20dp')
size_hint: 1, None
height: self.minimum_height
Then, in your code you can replace:
StudentsGridList().foo('4')
with:
sm.get_screen('studentHome').ids.sgl.foo('4')
And similarly for the other occurrences of StudentsGridList().foo()
.
As for the second problem, I am not sure of the purpose of that if
statement. Perhaps that if
statement should just be removed.