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

时间:2019-01-09 21:45:12

标签: python python-3.x kivy kivy-language

I'm working on a simple Kivy Popup and I'm confused as to why I can't reference my class variable, 'self.text_1', from within the constructor of the Popup class, but I can do so with the variable 'self.title'.

First, I'll start with the ubiquitous, "I'm new to Python and Kivy, so perhaps I'm just missing something obvious, but I'm at a loss."

I've tried to find answers, but nothing so far has seemed to cover this topic, at least in a way that I can understand and draw the connection. Below is my problem and some simplified code for demonstration.

From within the kv file > Label widget > text, I can refer to 'text_1' from the CustomPopup class in my py file by using 'root.text_1' when the variable is placed outside of the constructor (either before or after), but I cannot do so when placed within. The 'self.title' variable is setup the exact same way as 'self.text_1', but I CAN get that value without issue.

If I un-comment this line, using 'root.text_1' in the kv file returns the correct value.

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

If instead I try to use 'self.text_1' from within the constructor, I get an Attribute error. However, I have no issues using the variable 'self.title' just below 'self.text_1'.

AttributeError: 'CustomPopup' object has no attribute '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 )

What is the difference here as to why I can get the value from one constructor variable, but not another with ostensibly similar syntax?

I'm using Python 3.7.1 (conda version : 4.5.12) and 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

I would like to setup the text for my pop-up and use the str.format() method to insert a variable text element so that my message is tailored to the circumstances at hand, rather than generic or hard-coded with multiple options.

In this case, I pass an argument of 'foo' to the constructor, set the variable 'self.foo' equal to 'foo', then refer to 'self.foo' within my 'self.title' string and 'self.text_1' string.

If I place 'text_1' outside of the constructor, while I can retrieve the text value, since 'foo' hasn't been defined within that scope, I can't reference it to format my string.

I am interested in other solutions and any opportunity to learn, but ultimately, if there's a way to make this work without a workaround, that would be ideal.

Thanks in advance for any help. I've already learned a ton from everyone on this site.

P.S. - If I've done something "stupid" or offended your sensibilities, please provide a suggestion or correction rather than just berate me. Sometimes people get negative and it's (usually) not necessary.

1 个答案:

答案 0 :(得分:1)

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

首先,我没有像以前那样称呼“ self.title”。因此,我没有看到'self.title'与'self.text_1'有不同的行为;我看到了相同的行为。那么,如何才能显示标题而不显示内容?

“弹出”窗口小部件具有“标题”和“内容”的固有属性。当我在CustomPopup()中定义“ self.title”时,我只是提供了该属性的值。即使删除了相应的kv代码“ title:root.title”,仍会显示为“ self.title”定义的相同值。这是关键时刻,因为“ self.title”和“ self.text_1”这两个红色鲱鱼让我分心了。

一旦排除了我在两行本来相同的代码中看到不同行为的问题,我就会更深入地研究如何定义CustomPopup类。那时我碰到了展示如何正确处理该帖子的帖子:Kivy: How to get class Variables in Popup

长话短说...稍长一点...我更新了我的超级方法以继承我的'text_1'StringProperty,以便可以从CustomPopup对象中引用它!

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

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”,但标题仍可以正确显示。

下面的链接中显示的最终产品是Kivy弹出窗口,其中在kv文件中定义了结构/格式,并在Python中定义了功能和可变文本。对我来说,看起来比在Python方面做的要干净得多。

CustomPopupTest Working Solution

我希望这可以帮助其他人,例如许多其他职位对我有所帮助。