【问题标题】:How to pass a variable from Class to another Class?如何将变量从类传递到另一个类?
【发布时间】:2020-11-01 03:24:41
【问题描述】:

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

  1. 如果你运行我的代码,你会点击顶部菜单admin
  2. 然后点击任意mdchip
  3. 然后点击对话框窗口中的 etit 按钮。
  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()

我的应用.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

【问题讨论】:

    标签: python kivy kivy-language python-class


    【解决方案1】:

    根本原因:

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

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

    片段:

    <WindowManager>:
        ...
    
        Admin:
            id: scr_3
            name: 'admin'
        ...
    

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

    片段:

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

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

    解决方案:

    解决方案需要更改 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): 中删除get_admin = Admin()

    片段:

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

    输出:

    【讨论】:

    • 好眼力,ikolim。
    【解决方案2】:

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

    您为什么不直接查看Admin.my_string 内的EditArticle class

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

    def get_my_string():
        return my_string.value()
    

    然后你只需在 EditArticle 类中调用 Agent.get_my_string()

    【讨论】:

    • 它对我不起作用。如果我设置class Admin(Screen):my_string = StringProperty('hello world') 就可以了
    • 好吧,不幸的是我不习惯 StringProperty,这个类中没有你可以使用的 setter/getter 吗?
    【解决方案3】:

    这是我的问题的解决方案。 我必须将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()得到它

    【讨论】:

      猜你喜欢
      • 2014-01-03
      • 2013-02-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多