如何通过 add widget() 将 kivy 变量添加到 Screen

How to get a kivy variable added to Screen from add widget()

所以我正在尝试将一个变量添加到屏幕和我要添加的小部件中的 id, 所以如果我有这个:

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty

kv = """
Screen:
    cal:cal
    side: side

    GridLayout:
        rows: 1
        cols:2
        spacing:0

        GridLayout:
            rows: 5
            cols:1
            Button:
                text: "Cube"
                # on_press: app.mode = self.text
                on_press: app.setMode(self)
            Button:
                text: "Cuboid"
                on_press: app.setMode(self)
            Button:
                text: "Cylinder"
                on_press: app.setMode(self)
            Button:
                text: "Cone"
                on_press: app.setMode(self)
            Button:
                text: "Sphere"
                on_press: app.setMode(self)

        FloatLayout:

            Label:
                text: "The Volume and surface area of a {}:".format(app.mode)
                pos_hint: {"x":0.1, "y":0.8}
                text_size: self.size
            FloatLayout:
                id:cal
                Label:
                    text:"Side:"
                    pos_hint: {"x":1.1, "y":0.7}
                    text_size: self.size
                Label:
                    text:"Volume:"                
                    pos_hint: {"x":1.1, "y":0.65}
                    text_size: self.size
                Label:
                    text:"Surface Area:"                
                    pos_hint: {"x":1.1, "y":0.6}
                    text_size: self.size
                TextInput:
                    size_hint: (.4, None)
                    height: 26
                    multiline: False
                    pos_hint: {"x":1.24, "y":0.7}
                    id: side
                    text: app.sideText
                    on_text_validate: app.Cube_on_side_change(self)
                Label:                
                    text: app.volume
                    pos_hint: {"x":1.27, "y":0.65}
                    text_size: self.size
                Label:
                    text: app.surface_area
                    pos_hint: {"x":1.355, "y":0.6}
                    text_size: self.size
"""
cube = """
FloatLayout:
    Label:
        text:"Side:"
        pos_hint: {"x":1.1, "y":0.7}
        text_size: self.size
    Label:
        text:"Volume:"                
        pos_hint: {"x":1.1, "y":0.65}
        text_size: self.size
    Label:
        text:"Surface Area:"                
        pos_hint: {"x":1.1, "y":0.6}
        text_size: self.size
    TextInput:
        size_hint: (.4, None)
        height: 26
        multiline: False
        pos_hint: {"x":1.24, "y":0.7}
        id: side
        text: app.sideText
        on_text_validate: app.Cube_on_side_change(self)
    Label:                
        text: app.volume
        pos_hint: {"x":1.27, "y":0.65}
        text_size: self.size
    Label:
        text: app.surface_area
        pos_hint: {"x":1.355, "y":0.6}
        text_size: self.size"""

cuboid = """
FloatLayout:
    id:main
    Label:
        text:"Length:"
        pos_hint: {"x":1.1, "y":0.7}
        text_size: self.size
    Label:
        text:"Breadth:"                
        pos_hint: {"x":1.1, "y":0.65}
        text_size: self.size
    Label:
        text:"Height:"                
        pos_hint: {"x":1.1, "y":0.6}
        text_size: self.size
    TextInput:
        size_hint: (.4, None)
        height: 26
        multiline: False
        pos_hint: {"x":1.24, "y":0.7}
        id: length
        text: app.sideText
        on_text_validate: app.Cuboid_on_side_change(self)
    TextInput:
        size_hint: (.4, None)
        height: 26
        multiline: False
        pos_hint: {"x":1.24, "y":0.65}
        id: breadth
        text: app.sideText
        on_text_validate: app.Cube_on_side_change(self)
    TextInput:
        size_hint: (.4, None)
        height: 26
        multiline: False
        pos_hint: {"x":1.24, "y":0.6}
        id: height
        text: app.sideText
        on_text_validate: app.Cuboid_on_side_change()
    Label:                
        text: "Volume:"
        pos_hint: {"x":1.1, "y":0.55}
        text_size: self.size
    Label:
        text: "Surface Area:"
        pos_hint: {"x":1.1, "y":0.5}
        text_size: self.size
    Label:                
        text: app.volume
        pos_hint: {"x":1.27, "y":0.55}
        text_size: self.size
    Label:
        text: app.surface_area
        pos_hint: {"x":1.355, "y":0.5}
        text_size: self.size"""
cone = """
FloatLayout:
    Label:
        text:"Radius:"
        pos_hint: {"x":1.1, "y":0.7}
        text_size: self.size
    Label:
        text:"Height:"                
        pos_hint: {"x":1.1, "y":0.65}
        text_size: self.size
    TextInput:
        size_hint: (.4, None)
        height: 26
        multiline: False
        pos_hint: {"x":1.24, "y":0.7}
        id: Radius
        text: app.sideText
        on_text_validate: app.Cuboid_on_side_change(self)
    TextInput:
        size_hint: (.4, None)
        height: 26
        multiline: False
        pos_hint: {"x":1.24, "y":0.65}
        id: height
        text: app.sideText
        on_text_validate: app.Cube_on_side_change(self)
    Label:                
        text: "Volume:"
        pos_hint: {"x":1.1, "y":0.6}
        text_size: self.size
    Label:
        text: "Surface Area:"
        pos_hint: {"x":1.1, "y":0.55}
        text_size: self.size
    Label:                
        text: app.volume
        pos_hint: {"x":1.27, "y":0.6}
        text_size: self.size
    Label:
        text: app.surface_area
        pos_hint: {"x":1.355, "y":0.55}
        text_size: self.size
"""
screens = {
    "Cube": cube,
    "Cuboid": cuboid,
    "Cone": cone
}
class MyApp(App):
    sideText = StringProperty("")
    surface_area = StringProperty("0 cm²")
    volume = StringProperty("0 cm³")
    mode = StringProperty("Cube")

    def build(self):
        self.screen = Builder.load_string(kv)

        return self.screen

    def setMode(self, btn):
        self.volume = "0 cm³"
        self.surface_area = "0 cm³"
        self.mode = btn.text
        self.screen.cal.clear_widgets()
        self.screen.cal.add_widget(Builder.load_string(screens[self.mode]))

    def Cube_on_side_change(self, instance):

        try:
            value = float(instance.text)
            num = True
        except ValueError:
            # failed to convert
            num = False
            print("Numbers only idiot.")

        def cubeCalc(val):
            return {
                "volume": val * val * val,
                "surface_area": (val * val) * 6
            }

        if num:
            result = cubeCalc(value)
            self.volume = "{:.2f} cm³".format(result["volume"])
            self.surface_area = "{:.2f} cm²".format(result["surface_area"])

    def Cuboid_on_side_change(self):
        height = self.screen.cal.ids.main.height.text
        try:
            value = float(height)
            num = True
        except ValueError:
            # failed to convert
            num = False
            print("Numbers only idiot.")

        def cubeCalc(val):
            return {
                "volume": val * val * val,
                "surface_area": (val * val) * 6
            }

        if num:
            result = cubeCalc(value)
            self.volume = "{:.2f} cm³".format(result["volume"])
            self.surface_area = "{:.2f} cm²".format(result["surface_area"])


if __name__ == "__main__":
    MyApp().run() 

on_text_validateTextInput 和字符串长方体中的 id:height,我想从文本输入中获取文本,例如:self.screen.main.height.text,但是,为此,我必须将 main:mainheight:height 添加到 Screen。我该怎么做?

我建议重构您的代码。与其重新发明 ScreenManager 的功能,不如使用 ScreenManager。在您的 kv 字符串中,将 FloatLayout 替换为:

ScreenManager:
    CubeScreen:
    CuboidScreen:
    ConeScreen:

并使用额外的 kv 字符串(如 cube)作为 kv 字符串中额外规则的基础。类似于:

<CubeScreen>:
    Label:
        text: "The Volume and surface area of a Cube:"
        pos_hint: {"x":0.1, "y":0.8}
        text_size: self.size
        FloatLayout:
            Label:
                text:"Side:"
                pos_hint: {"x":0.1, "y":0.7}
                text_size: self.size
         .
         .
         .

并在 py 中定义每个 Screen class,例如:

class CubeScreen(Screen):
    def get_cube_area(self):
        .
        .
        .

并且在每个新的 classes(如 CubeScreen)中,您可以定义计算面积、体积等的方法,并且您可以使用它们轻松访问 TextInputs ids。每个 Screen 中的 on_text_validate 都可以从 Screen 中调用适当的方法(如 on_text_validate: root.get_cube_area())。