I am using Kivy and Kivymd. I have a problem with passing a variable between class Admin
and class EditArticle
. I need to pass my_string
from Admin to EditArticle. I am trying to do this, but getting an empty string.
So, in class Admin
I have my_string
. Then, in a method edit_article
of class Admin
i am setting value 'some text' for my_string
. Then I am trying to get it in the method edit
of class EditArticle
. But it is empty all the time. I really cannot figure it out.
admin
.mdchip
.my_string
(but it always empty).This is my App.py
from kivy.clock import Clock
from kivymd.app import MDApp
from kivy.properties import StringProperty, NumericProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.card import MDCard
from kivymd.uix.chip import MDChip
from kivy.core.window import Window
Window.size = (600, 853)
from kivymd.uix.menu import MDDropdownMenu
from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import RectangularElevationBehavior
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDFlatButton
from kivymd.uix.dialog import MDDialog
class WindowManager(ScreenManager):
pass
class AdminFooter(ThemableBehavior, RectangularElevationBehavior, MDBoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.md_bg_color = self.theme_cls.primary_color
class ToolbarBack(ThemableBehavior, RectangularElevationBehavior, MDBoxLayout):
pass
class CustomToolbar(ThemableBehavior, RectangularElevationBehavior, MDBoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.md_bg_color = self.theme_cls.primary_color
Clock.schedule_once(self.create_menu, 1)
def create_menu(self, i):
self.items = ['admin', 'settings']
menu_items = [{"text": f"{i}"} for i in self.items]
self.menu = MDDropdownMenu(
caller=self.ids.button_2, items=menu_items, width_mult=4, callback=self.get_item
)
def get_item(self, instance):
self.menu.dismiss()
App.get_running_app().window_manager.current = instance.text
class Content(BoxLayout):
pass
class Admin(Screen):
dialog_get_article = None
my_string = StringProperty() # My string
def __init__(self, **kwargs):
super().__init__(**kwargs)
def get_article(self, instance,*args):
self.dialog_get_article = MDDialog(
title="Click the EDIT",
buttons=[
MDFlatButton(
text="EDIT",
on_release = self.edit_article
),
],
)
self.dialog_get_article.open()
def edit_article(self, instance):
self.my_string = 'some text' # set value
App.get_running_app().window_manager.current = 'edit-article'
self.dialog_get_article.dismiss()
def on_enter(self, *args):
data = [
{'id': 1, 'title': 'Arcicle 1', 'body': 'body of Article 1'},
{'id': 2, 'title': 'Arcicle 2', 'body': 'body of Article 2'},
{'id': 3, 'title': 'Arcicle 3', 'body': 'body of Article 3'}
]
for x in data:
chip = BlogChip(id=x.get('id'), title=x.get('title'), body=x.get('body'))
self.ids.box.add_widget(chip)
class EditArticle(Screen):
var = StringProperty()
def edit(self, instance):
print(self.var, ' << it is goingt to be <my_string> from Admin')
class UserSettings(Screen):
pass
class BlogChip(MDChip):
get_admin = Admin()
id = NumericProperty()
title = StringProperty()
body = StringProperty()
class BlogCard(MDCard):
pass
class Detail(Screen):
pass
class ResultSearch(Screen):
pass
class Container(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Clock.schedule_once(self.create_cards)
def create_cards(self, i):
pass
class App(MDApp):
def callback(self):
self.window_manager.current = 'container'
def build(self):
self.theme_cls.primary_palette = 'Indigo'
self.window_manager = WindowManager()
return self.window_manager
App().run()
My app.kv
<WindowManager>
Container:
id: scr_1
name: 'container'
Detail:
id: scr_2
name: 'detail'
Admin:
id: scr_3
name: 'admin'
EditArticle:
id: scr_4
name: 'edit-article'
var: scr_3.my_string # <---------
ResultSearch:
id: scr_5
name: 'result-search'
UserSettings:
id: scr_6
name: 'settings'
<Admin>:
BoxLayout:
id: boxlayout_1
orientation: 'vertical'
MDToolbar:
pos_hint: {'top': 1}
title: 'Admin Blog'
left_action_items: [["arrow-left", lambda x: app.callback()]]
ScrollView:
MDStackLayout:
adaptive_height: True
padding: 10
spacing: dp(5)
id: box
<EditArticle>
MDToolbar:
title: 'Admin Blog'
MDLabel:
text: str(root.var)
MDRaisedButton:
text: 'click me to see a variable in console'
pos_hint: {'center_x': .5, 'center_y': .5}
on_release: root.edit(root)
<MyToolbar@CustomToolbar>:
size_hint_y: None
height: self.theme_cls.standard_increment
padding: "25dp"
spacing: "12dp"
MDLabel:
id: label
text: 'Blog'
font_style: 'H6'
theme_text_color: "Custom"
text_color: 1,1,1,1
Widget:
MDIconButton:
id: button_2
icon: "dots-vertical"
pos_hint: {"center_y": .5}
theme_text_color: "Custom"
text_color: 1,1,1,1
on_release: root.menu.open()
<Container>
BoxLayout:
orientation: 'vertical'
MyToolbar:
MDLabel:
text: 'Go To menu (dot-vertical/admin'
halign: 'center'
<BlogCard>
<Detail>:
<BlogChip>
label: root.title
icon: ''
callback: root.get_admin.get_article
In your app, there are two instances of class Admin
instantiated.
This first instance was instantiated in the kv file when you instantiated the root, WindowManager()
in the build
method.
<WindowManager>:
...
Admin:
id: scr_3
name: 'admin'
...
The second instance was instantiated in the class BlogChip
.
class BlogChip(MDChip):
get_admin = Admin()
...
The class attribute, my_string
was updated in the second instance of class Admin
.
But the screen is referencing the instance instantiated by the root. Therefore, the app displayed empty string.
The solution requires changes to the kv and python files.
Replace
callback: root.get_admin.get_article
with
callback: app.root.ids.scr_3.get_article
<BlogChip>
label: root.title
icon: ''
callback: app.root.ids.scr_3.get_article
get_admin = Admin()
in class BlogChip(MDChip):
class BlogChip(MDChip):
id = NumericProperty()
title = StringProperty()
body = StringProperty()
edit()
initialize class attribute, var
class EditArticle(Screen):
var = StringProperty()
def edit(self, instance):
# Each screen has by default a property manager that
# gives you the instance of the ScreenManager used.
self.var = self.manager.ids.scr_3.my_string
print(self.var, ' << it is going to be <my_string> from Admin')