I've been encountering an issue when trying to implement screen manager with Kivy. As you can see the 'chat' id is defined in main.kv so I can't understand why the error is occurring. I'm new with Kivy and have never used screen manager before.. please help!
app_cleaned.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.clock import mainthread
from range_key_dict import RangeKeyDict
from math import inf
from threading import Thread
from powerBot import ChatBot
#remove
from kivy.clock import Clock
Window.size = (500, 500)
class SignupScreen(Screen):
pass
class MainScreen(Screen):
pass
class Message(Label):
pass
class User:
def __init__(self, years_lifting, weight, height, unavailable_equipment, unavailable_muscle_groups, aim):
# Lifting experience classification
expClassDict = RangeKeyDict({
(0.0, 1.9): 1, # beginner
(2.0, 3.9): 2, # intermediate
(4, inf): 3 # advanced
})
expClass = expClassDict[years_lifting]
# BMI classification
bmiClassDict = RangeKeyDict({
(0.0, 9.9): 1, # severely underweight
(10.0, 18.5): 2, # underweight
(18.6, 24.9): 3, # healthy weight
(25.0, 34.9): 2, # overweight
(35.0, inf): 1, # severely overweight
})
bmi = weight/(height/100)**2 # calculate BMI
bmiClass = bmiClassDict[bmi]
self.experience_level = expClass
self.bmi_level = bmiClass
self.unavailable_equipment = unavailable_equipment
self.unavailable_muscle_groups = unavailable_muscle_groups
self.aim = aim
class ExampleApp(App):
def build(self):
sm = ScreenManager()
# Load the signup.kv file and add its content to the SignupScreen
Builder.load_file('signup.kv')
# Create the SignupScreen instance and add it to the ScreenManager
signup_screen = SignupScreen(name='signup')
sm.add_widget(signup_screen)
# Load the main application screen from main.kv
Builder.load_file('main.kv')
main_screen = MainScreen(name='main')
sm.add_widget(main_screen)
return sm
def switch_to_main_screen(self):
self.root.current = 'main'
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.ai = ChatBot("PowerBot")
def on_start(self):
print("Root IDs:", self.root.ids)
# Assuming you expect 'chat' to be available here, you can print its contents as well
if 'chat' in self.root.ids:
print("Chat Widget:", self.root.ids.chat)
self.root.current = 'signup'
initial_messages = ["PowerBot is initializing, please wait (this could take a minute)"]
for message in initial_messages:
self.system_message(message)
message = "000000"
thread = Thread(target=self.background_message_receiver,args=(message,))
thread.start()
self.root.ids.sv.scroll_y = 0
def sign_up(self, years_lifting, weight, height):
# Convert input values to appropriate data types (e.g., int, float)
years_lifting = float(years_lifting)
weight = float(weight)
height = float(height)
# Create a User object with the provided sign-up details
user = User(years_lifting, weight, height) # Pass other sign-up details as needed
self.root.ids.years_lifting_input.text = ''
self.root.ids.weight_input.text = ''
self.root.ids.height_input.text = ''
def background_message_receiver(self, message):
response = self.ai.message_to_bot(message)
self.incoming_message(response)
def send_message(self, message):
self.root.ids.ti.text = ""
if message:
m = Message(text=f"[color=dd2020]You[/color] > {message}")
self.root.ids.chat.add_widget(m)
self.root.ids.ti.focus = True
thread = Thread(target=self.background_message_receiver,args=(message,))
thread.start()
@mainthread
def incoming_message(self, message):
m = Message(text=f"[color=20dd20]PowerBot[/color] > {message}")
self.root.ids.chat.add_widget(m)
self.root.ids.ti.focus = True
def system_message(self, message):
m = Message(text=f"[color=ffffff]System[/color] > {message}")
self.root.ids.chat.add_widget(m)
self.root.ids.ti.focus = True
# Execute
if __name__ == '__main__':
ExampleApp().run()
main.kv
<Message>:
size_hint: 1, None
text_size: self.width, None
size: self.texture_size
markup: True
<MainScreen>:
BoxLayout:
orientation: 'vertical'
padding: 10
ScrollView:
id: sv
BoxLayout:
id: chat # Add the ID for the chat messages
spacing: 5
padding: 10
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
Widget: # used as a spacer, push message to bottom
size_hint_y: None
height: sv.height
BoxLayout:
size_hint_y: None
height: 40
spacing: 10
TextInput:
id: ti
multiline: False
on_text_validate: app.send_message(self.text)
Button:
text: 'submit'
size_hint_x: None
width: 75
on_release: app.send_message(ti.text)
signup.kv
<SignupScreen>:
BoxLayout:
orientation: 'vertical'
padding: 10
Button:
text: 'Continue'
size_hint_y: None
height: '48dp'
on_release: app.switch_to_main_screen()
I have seen the other question on here regarding a similar issue but unfortunately I'm not proficient enough with Kivy to apply the solutions to my specific scenario.
Your chat
id is defined in the MainScreen
class, but you are trying to access it in self.root.ids
of the ExampleApp
. Since that id is defined in the <MainScreen>
rule, you must access it through the MainScreen
instance. One way to do that is to just save a reference to the MainScreen
instance. In your build()
method you can change:
# Load the main application screen from main.kv
Builder.load_file('main.kv')
main_screen = MainScreen(name='main')
sm.add_widget(main_screen)
to:
# Load the main application screen from main.kv
Builder.load_file('main.kv')
self.main_screen = MainScreen(name='main')
sm.add_widget(self.main_screen)
Then, anywhere inside any non-static ExampleApp
method, you can access the chat
id as:
self.main_screen.ids.chat