为什么我不能在我的 kv 文件的构造函数中引用 self.text_1?

Why can't I reference self.text_1 in the constructor from my kv file?

我正在开发一个简单的 Kivy Popup,我很困惑为什么我不能从 Popup [=] 的构造函数中引用我的 class 变量 'self.text_1' 75=],但我可以使用变量 'self.title'.

首先,我将从无处不在的,"I'm new to Python and Kivy, so perhaps I'm just missing something obvious, but I'm at a loss."

我试图找到答案,但到目前为止似乎没有任何内容涵盖这个主题,至少在某种程度上我可以理解并得出联系。下面是我的问题和一些用于演示的简化代码。

在 kv 文件 > 标签小部件 > 文本中,当变量放在外部时,我可以通过使用 'root.text_1' 从我的 py 文件中的 CustomPopup class 引用 'text_1'构造函数的(之前或之后),但放在其中时我不能这样做。 'self.title' 变量的设置方式与 'self.text_1' 完全相同,但我可以毫无问题地获取该值。

如果我取消注释这一行,在 kv 文件中使用 'root.text_1' returns 正确的值。

class CustomPopup( Popup ):
    # I can reference this text from the kv file using "root.text_1"
    # text_1 = 'blah blah blah'

如果我尝试从构造函数中使用 'self.text_1',则会收到属性错误。但是,使用 'self.text_1'.

下方的变量 'self.title' 没有问题

AttributeError: 'CustomPopup' 对象没有属性 'text_1'

def __init__( self, foo = 'bar' ):
    super().__init__()
    self.foo =  foo

    # I can't reference this text from the kv file using "root.text_1". Why?
    self.text_1 = 'blah blah {foo}'.format( foo = self.foo )

    # I can reference this text from the kv file using "root.title"
    self.title = 'Title {foo}!'.format( foo = self.foo )

为什么我可以从一个构造函数变量中获取值,但不能从表面上类似语法的另一个构造函数变量中获取值,这有什么区别?

我正在使用 Python 3.7.1(conda 版本:4.5.12)和 Kivy 1.10.1。

Python:

import kivy
from kivy import Config
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.popup import Popup


kivy.require( '1.10.1' )


Config.set( 'graphics', 'fullscreen', 0 )
Config.set( 'graphics', 'height', 600 )
Config.set( 'graphics', 'width', 800 )
Config.set( 'graphics', 'resizable', 0 )
Config.set( 'kivy', 'exit_on_escape', 0 )


class CustomPopup( Popup ):
    # I can reference this text from the kv file using "root.text_1"
    # text_1 = 'blah blah blah'

    def __init__( self, foo = 'bar' ):
        super().__init__()
        self.foo =  foo

        # I can't reference this text from the kv file using "root.title". Why?
        self.text_1 = 'blah blah {foo}'.format( foo = self.foo )

        # I can reference this text from the kv file using "root.title"
        self.title = 'Title {foo}!'.format( foo = self.foo )


class CustomPopupTestApp( App ):
    def build( self ):
        return CustomPopup()


#Instantiate top-level/root widget and run it
if __name__ == "__main__":
    CustomPopupTestApp().run()

kv:

<CustomPopup>:
    id: popup
    title: root.title
    title_size: 30
    title_align: 'center'
    size_hint: 0.8, 0.8
    auto_dismiss: False
    pos_hint: { 'x' : 0.1 , 'y' : 0.1 }

    GridLayout:
        cols: 1
        rows: 2
        spacing: 15
        padding: 15

        Label:
            id: content
            text: root.text_1
            font_size: 25
            padding: 15, 25
            size_hint_y: None
            text_size: self.width, None
            height: self.texture_size[ 1 ]
            halign: 'center'

        GridLayout:
            cols: 2
            rows: 1

            AnchorLayout:
                anchor_x : 'center'
                anchor_y : 'bottom'
                padding: 20

                Button:
                    id: yes
                    text: 'Yes'
                    font_size: 30
                    size_hint: 0.8, 0.4

            AnchorLayout:
                anchor_x : 'center'
                anchor_y : 'bottom'
                padding: 20

                Button:
                    id: no
                    text: 'No'
                    font_size: 30
                    size_hint: 0.8, 0.4

我想为我的弹出窗口设置文本并使用 str.format() 方法插入可变文本元素,以便我的消息根据手头的情况量身定制,而不是通用或带有多个选项的硬编码。

在这种情况下,我将参数 'foo' 传递给构造函数,将变量 'self.foo' 设置为等于 'foo',然后在我的 'self.title' 字符串和 'self.text_1' 字符串。

如果我将 'text_1' 放在构造函数之外,虽然我可以检索文本值,但由于 'foo' 尚未在该范围内定义,我无法引用它来格式化我的字符串.

我对其他解决方案和任何学习机会都很感兴趣,但最终,如果有一种方法可以在没有解决方法的情况下完成这项工作,那将是理想的。

在此先感谢您的帮助。我已经从这个网站上的每个人那里学到了很多东西。

P.S。 - 如果我做了什么 "stupid" 或冒犯了你的感情,请提供建议或更正,而不仅仅是责备我。有时人们会变得消极,这(通常)是没有必要的。

通过研究和测试,我找到了答案。

事实证明,首先,我并没有像我想的那样打电话给 'self.title'。因此,我没有看到 'self.title' 与 'self.text_1' 的不同行为;我看到了同样的行为。那么,我怎么才能显示我的标题,而不是我的内容呢?

Popup 小部件具有 'title' 和 'content' 的固有属性。当我在 CustomPopup() 中定义 'self.title' 时,我只是提供了该属性的值。即使在删除相应的 kv 代码 'title: root.title' 之后,仍然显示为 'self.title' 定义的相同值。这是关键时刻,因为我被 'self.title' vs 'self.text_1'.

的转移注意力分散了注意力

在我排除了我看到两行相同代码的不同行为的问题后,我更深入地研究了我是如何定义我的 CustomPopup class。那是我遇到这个 post 的时候,它演示了如何正确处理这个问题:Kivy: How to get class Variables in Popup.

长话短说...略短...我更新了超级方法以继承我的 'text_1' StringProperty 以便我可以从 CustomPopup object!

中引用它

这是更新后的工作解决方案:

Python:

import kivy
from kivy import Config
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.properties import StringProperty

kivy.require( '1.10.1' )

Config.set( 'graphics', 'fullscreen', 0 )
Config.set( 'graphics', 'height', 600 )
Config.set( 'graphics', 'width', 800 )
Config.set( 'graphics', 'resizable', 0 )
Config.set( 'kivy', 'exit_on_escape', 0 )



class CustomPopup( Popup ):

    text_1 = StringProperty( '' )

    def __init__( self, foo = 'bar' ):
        super( CustomPopup, self ).__init__()

        self.foo =  foo

        self.text_1 =  'blah blah {foo}'.format( foo = self.foo )

        self.title = 'Title {foo}!'.format( foo = self.foo )


class CustomPopupTestApp( App ):
    def build( self ):
        blarg = CustomPopup()
        return blarg


#Instantiate top-level/root widget and run it
if __name__ == "__main__":
    CustomPopupTestApp().run()

kv:

<CustomPopup>:
    id: popup
    # title: root.title
    title_size: 30
    title_align: 'center'
    size_hint: 0.8, 0.8
    auto_dismiss: False
    pos_hint: { 'x' : 0.1 , 'y' : 0.1 }

    GridLayout:
        cols: 1
        rows: 2
        spacing: 15
        padding: 15

        Label:
            id: content
            text: root.text_1
            font_size: 25
            padding: 15, 25
            size_hint_y: None
            text_size: self.width, None
            height: self.texture_size[ 1 ]
            halign: 'center'

        GridLayout:
            cols: 2
            rows: 1

            AnchorLayout:
                anchor_x : 'center'
                anchor_y : 'bottom'
                padding: 20

                Button:
                    id: yes
                    text: 'Yes'
                    font_size: 30
                    size_hint: 0.8, 0.4

            AnchorLayout:
                anchor_x : 'center'
                anchor_y : 'bottom'
                padding: 20

                Button:
                    id: no
                    text: 'No'
                    font_size: 30
                    size_hint: 0.8, 0.4

请注意,kv 文件不再引用 'root.title',但标题仍能正常显示。

下面 link 中显示的最终产品是一个 Kivy 弹出窗口,其 structure/formatting 在 kv 文件中定义,功能和变量文本在 Python 中定义。对我来说,它看起来比在 Python 侧完成所有操作要干净得多。

CustomPopupTest Working Solution

我希望这对其他人有帮助,就像许多其他 post 帮助过我一样。