Hi to all kivy/python experts. I am looking for an advice/solution, after trying everything I found for the last week.
When trying to write the result from foo2() into my text label (my_label) in screenTwo, **foo2() **fails to instantiate the ids of the screen 2 (throwing all sorts of errors, depending on the things I tried (see below).
I can understand the reason: The moment I am calling foo2() from foo1() we are exiting the screenTwo as a parent for my_label, which changes the "self" context (of self.ids.my_label.text = result from foo2()). This now no longer refers to screenTwo, but probably to the in-memory address of the foo2() function which I think now acts as a parent (at least this is what I concluded, I am still a beginner in python).
Basically everything I could find, to try and find the "real" parent that I need to enumerate, to find the children IDs where my_label actually is, but wasn't able to:
tried declaring an ObjectProperty = None inside my Screen2 class, then give an id to my label and then a variable name which refers to that id inside my Screen2 class. This is recommended by many tutorials, but this is working when passing things between screens, not in my case.
tried changing (inside foo2()) the reference to the destination of the label, from self.ids to
Depending on what I've tried (many tries) I received various errors. Here's some:
- kivy AttributeError: 'super' object has no attribute 'getattr' thread here also
- NameError: name 'root' is not defined
- AttributeError: 'str' object has no attribute 'text'
- Kivy AttributeError: 'NoneType' object has no attribute 'ids'
I do not seem to understand how this self/root/app context works, despite looking up at various resources (stackoverflow, pdf files, kivy official documentation) (if someone could recommend a good tutorial or explain for all newbies like me out there...wow how helpful it would be).
Also, I couldn't find anything related to whether this is actually possible, considering that from within the class that holds the current screen you're actually calling an external function located in another py file: **does kivy even support passing down responses from external functions back to the main function? **(I assume it does, since this is pure python, not kivy. kivy just manages the writing, within the correct context....if I were just able to figure it out :( ).
Anyway, here's my sample code (py + kv file). If any of you could give me a hint or a solution to how I could call a function which calls an external function which then writes the response back on the screen from which I started the events, in a label, I would be very thankful!
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.app import MDApp
from kivy.app import App
from kivymd.uix.label import MDLabel
from kivy.properties import ObjectProperty, StringProperty
import external
class Screen1Main(Screen):
pass
class Screen2(Screen):
def foo1():
# 1. do something
myArg = "x"
# 2. then call foo2()
external.myExternalClass.foo2(myArg)
class WindowManager(ScreenManager):
pass
class MainApp(MDApp):
def __init__(self, **kwargs):
self.title = "My Application"
super().__init__(**kwargs)
if __name__ == "__main__":
MainApp().run()
external.py
from kivy.app import App
import main
class myExternalClass:
def foo2(arg1):
#1. does something
blabla
#2. gets the result
myResult = "anything"
#3. tries to write the result into my_label (located in Screen 2, which is a child
# of my main app (in file: main.py), who manages the multi-screen via a screen manager within
# WindowsManager class)
Screen2.manager.get_screen("screenTwo").ids.my_label.text = myResult
---
WindowManager:
Screen1Main:
id: id_screenOne
Screen2:
id: id_screenTwo
<Screen1Main>:
name: "screenOne"
GridLayout:
<rest of layout here>
<Screen2>:
name: "screenTwo"
GridLayout:
cols: 2
MDLabel:
id: my_label
text: "-"
MDIconButton:
id: my_button
icon: "message-arrow-left"
on_release: root.foo1(arg0)
# Things I tried:
Basically everything I could find, as described above.
Try using:
MDApp.get_running_app().root.get_screen('screenTwo').ids.my_label.text = myResult
in your foo2()
method. This gets the MDApp
and references its root
(the WindowManager
) to get the the desired Screen
.