FYI: I'm really new to coding - one of my first time using Stack Overflow so be patient please.
Aim: I am trying to take in user input on Screen1, create an instance of the Player class, store those instances in a list, then iterate over that list to create a MyRowWidget for each 'player' in that list.
The problem: the automatic creation of rows doesn't seem to be working based of the list of players from user input. It may have something to do with passing information between screens
Please feel free to ask any clarifying questions and I will amend. Thank you in advance for your help.
My code (i've reduced this as much as possible, I believe).
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import ScreenManager, Screen
class Player:
def __init__(self, name):
self.name = name
self.stats = {
"2-pt FG MADE": 0,
"2-pt FG Missed": 0,
}
class HeaderRowWidget(GridLayout):
def __init__(self, **kwargs):
super(HeaderRowWidget, self).__init__(**kwargs)
self.cols = 4
self.add_widget(Label(text="Player Name"))
self.add_widget(Label(text="Shirt Number"))
self.add_widget(Label(text="2-pt FG MADE"))
self.add_widget(Label(text="2-pt FG Missed"))
class MyRowWidget(GridLayout):
def __init__(self, player, **kwargs):
super(MyRowWidget, self).__init__(**kwargs)
self.cols = 4
self.player = player
self.name_label = Label(text=player.name)
self.shirt_number_label = Label(text="default")
self.add_widget(self.name_label)
self.add_widget(self.shirt_number_label)
# Add buttons to the layout (add your buttons here)
button_labels = ["2-pt FG MADE", "2-pt FG Missed"]
self.buttons = {}
for label in button_labels:
button = Button(text="+")
self.buttons[label] = button
self.add_widget(button)
class MyScreenManager(ScreenManager):
def __init__(self, **kwargs):
super(MyScreenManager, self).__init__(**kwargs)
self.screen1 = Screen1(name="screen1")
self.add_widget(self.screen1)
# Create Screen2 with the 'players' argument
self.screen2 = Screen2(name="screen2", players=self.screen1.players)
self.add_widget(self.screen2)
class Screen1(Screen):
def __init__(self, **kwargs):
super(Screen1, self).__init__(**kwargs)
self.players = [] # List to store player objects
# Create a layout for the screen
layout = BoxLayout(orientation='vertical', spacing=10)
# Create widgets and add them to the layout
self.player_input = TextInput(hint_text="Enter player name")
add_button = Button(text="Add Players")
add_button.bind(on_press=self.add_players_and_teams)
# add button to go to next screen
next_screen_button = Button(text="Next screen")
next_screen_button.bind(on_press=self.switch_screen2)
layout.add_widget(self.player_input)
layout.add_widget(add_button)
layout.add_widget(next_screen_button)
# add layout to the screen
self.add_widget(layout)
def add_players_and_teams(self, instance):
player_name = self.player_input.text.strip()
if player_name:
player = Player(player_name)
self.players.append(player)
self.player_input.text = ""
def switch_screen2(self, instance):
# Access the ScreenManager and change the current screen to Screen2
self.manager.current = "screen2"
#code to test 'for player in xyz' logic of Screen2
player1 = Player("Wes")
player2 = Player("James")
player_list = [player1, player2]
class Screen2(Screen):
def __init__(self, players, **kwargs):
super(Screen2, self).__init__(**kwargs)
layout = BoxLayout(orientation='vertical', spacing=10)
header_widget = HeaderRowWidget()
layout.add_widget(header_widget)
for player in players:
player_widget = MyRowWidget(player=player)
layout.add_widget(player_widget)
self.add_widget(layout)
class MyApp(App):
def build(self):
return MyScreenManager()
if __name__ == '__main__':
MyApp().run()
I would expect in Screen 2, automatic rows with buttons to popup for each player that the user has inputted.
For example: if you substitute a random list of players based on the Player class, it seems to work perfectly. For example, pass 'player_list' (located just above 'screen2' class - a list I created myself for testing purposes,) to the 'for player in [insert player_list]' loop in Screen2 and it works as intended.
What I've tried: I've tried working with ChatGPT in a million variations to see if it's something to do with how information is passed between screens, or if it's to do with the way the list is created from user input (using print statements) but nothing seems to give a clear reason. I was hoping someone with Kivy experience might have come across a similar issue before
The problem is that self.screen2 = Screen2(name="screen2", players=self.screen1.players)
is called inside the __init__()
method of MyScreenManager
. At that point, there are no items in the players
list of Screen1
, so Screen2
is created with no players. You must add the players to Screen2
after the user inputs them. To do this you can modify the Screen2
class to provide a method for adding players:
class Screen2(Screen):
def __init__(self, players, **kwargs):
super(Screen2, self).__init__(**kwargs)
self.layout = BoxLayout(orientation='vertical', spacing=10)
header_widget = HeaderRowWidget()
self.layout.add_widget(header_widget)
for player in players:
player_widget = MyRowWidget(player=player)
self.layout.add_widget(player_widget)
self.add_widget(self.layout)
def add_player(self, player):
self.layout.add_widget(MyRowWidget(player=player))
Then that new method can be used to add players to Screen2
, for example, in the switch_screen2()
:
def switch_screen2(self, instance):
# Access the ScreenManager and change the current screen to Screen2
self.manager.current = "screen2"
scr2 = self.manager.get_screen('screen2')
for player in self.players:
scr2.add_player(player)
Of course, there are details to be handled, but this should give you a starting point.