如何将变量从 Class 传递到另一个 Class?

How to pass a variable from Class to another Class?

我正在使用 Kivy 和 Kivymd。我在 class Adminclass EditArticle 之间传递变量时遇到问题。我需要将 my_string 从 Admin 传递给 EditArticle。我正在尝试这样做,但得到一个空字符串。 所以,在 class Admin 我有 my_string。然后,在 class Admin 的方法 edit_article 中,我为 my_string 设置值 'some text'。然后我试图在 class EditArticle 的方法 edit 中获取它。但它一直是空的。实在想不通

  1. 如果您 运行 我的代码,您将点击顶部菜单 admin
  2. 然后单击任意 mdchip
  3. 然后单击对话框中的 etit 按钮 window。
  4. 然后点击按钮得到my_string(但它总是空的)。

这是我的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()

我的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

我不太明白你的代码在做什么?

为什么不直接看Admin.my_string里面的EditArticle class

如果这不起作用,您是否尝试为您的 my_string 属性创建一个 getter
抱歉,我不知道 StringProperty 是如何工作的...但是您不能在 Agent class 中执行以下操作吗?

def get_my_string():
    return my_string.value()

然后您只需在 EditArticle class 中调用 Agent.get_my_string()

这是我的问题的解决方案。 我必须将 EditArticle.my_string = self.my_string 添加到 class Admin,如下所示:

def edit_article(self, instance):
    EditArticle.my_string = self.my_string
    App.get_running_app().window_manager.current = 'edit-article'
    self.dialog_get_article.dismiss()

之后我可以在class EditArticle()

中得到它

根本原因:

在您的应用中,实例化了两个 class Admin 实例。

第一个实例是在您实例化根时在 kv 文件中实例化的,WindowManager()build 方法中。

片段:

<WindowManager>:
    ...

    Admin:
        id: scr_3
        name: 'admin'
    ...

第二个实例在class BlogChip中实例化。

片段:

class BlogChip(MDChip):
    get_admin = Admin()
    ...

class 属性 my_string 已在 class Admin 的第二个实例中更新。 但是屏幕正在引用由根实例化的实例。因此,应用程序显示空字符串。

解决方案:

该解决方案需要更改 kv 和 python 文件。

kv 文件:

替换 callback: root.get_admin.get_articlecallback: app.root.ids.scr_3.get_article

片段:

<BlogChip>
    label: root.title
    icon: ''
    callback: app.root.ids.scr_3.get_article

Python 文件:

  1. 删除 class BlogChip(MDChip):
  2. 中的 get_admin = Admin()

片段:

class BlogChip(MDChip):
    id = NumericProperty()
    title = StringProperty()
    body = StringProperty()
  1. 方法中,edit()初始化class属性,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')

输出: