Kivy:无法更新来自另一个 class 的文本输入值

Kivy: Can't update text input value from another class

我是 kivy 的新手。我正在尝试从另一个 class 更改文本输入值(TextInput 框中显示的字符串值),但没有通过。

我在 class MyFirstScreen 中有以下小部件:

我想做的事情:RecycleView 中的每个项目被选中时,TextInputs 应该更新并加载所选项目 dictionary.

但是当我尝试从另一个 class (class SelectableLabel) 访问当前 TextInput 的值时:

class SelectableLabel(RecycleDataViewBehavior, Label):
    #...
    def update_text_inputs(self, *kwarg):
        my_text_input = MyFirstScreen().ids.system_name_text_input_id #<--i can access to widget
        print("my_print_val is:", my_text_input.text) #<--but widget's current text value is : ''
        my_text_input.text = "Updated Value"

我可以访问 my_text_input 小部件,但它的文本 (my_text_input.text) 是一个空字符串 ('')。此外,当我更改 my_text_input.text 的值时, TextInput 的盒子里没有任何反应。

有谁知道我在这里做错了什么或如何让它工作?提前谢谢你...

这是我的 .py 代码:

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.properties import BooleanProperty
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior


class Manager(ScreenManager):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)


class MyFirstScreen(Screen):
    system_name_text_input_id = ObjectProperty(None)

    def __init__(self, **kwarg):
        super().__init__(**kwarg)
        print("__init__ of MyFirstScreen is Called")

    def get_text_inputs(self):
        ret_val = self.ids.system_name_text_input_id.text
        print("get_text_input is called, ret_val:", ret_val)
        return ret_val


class RecycleViewWidget(RecycleView):
    def __init__(self, **kwargs):
        super(RecycleViewWidget, self).__init__(**kwargs)
        self.items_of_rv = []
        for i in range(1, 21):
            self.items_of_rv.append(
                {"color": (0, 0, 0, 1), "font_size": "20", "text": f"User {i}",
                 "user_id": f"{100 * i}"})
        self.data = [item for item in self.items_of_rv]


class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout):
    """ Adds selection and focus behaviour to the view. """


class SelectableLabel(RecycleDataViewBehavior, Label):
    """ Add selection support to the Label """
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)

    def refresh_view_attrs(self, rv, index, data):
        """ Catch and handle the view changes """
        self.index = index
        return super(SelectableLabel, self).refresh_view_attrs(rv, index, data)

    def on_touch_down(self, touch):
        """ Add selection on touch down """
        if super(SelectableLabel, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            return self.parent.select_with_touch(self.index, touch)

    def apply_selection(self, rv, index, is_selected):
        """ Respond to the selection of items in the view. """

        self.selected = not is_selected
        if is_selected:
            rv.data[index].update({'color': (1, 1, 1, 1)})
            self.refresh_view_attrs(RecycleViewWidget(), index, rv.data[index])
            print("selection changed to {0}".format(rv.data[index]))
            self.update_text_inputs()
        else:
            if rv.data[index].get("color") == (1, 1, 1, 1):
                rv.data[index].update({'color': (0, 0, 0, 1)})
                self.refresh_view_attrs(RecycleViewWidget(), index, rv.data[index])
        self.selected = not self.selected

    def update_text_inputs(self, *kwarg):
        my_text_input = MyFirstScreen().ids.system_name_text_input_id#<--i can access to widget
        print("my_print_val is:", my_text_input.text)#<--but widget's current text value is : ''
        # my_text_input.text = "Updated Value" 

main_style = Builder.load_file("test.kv")


class MyApp(App):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def build(self):
        return main_style


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

还有我的.kv代码:

Manager:
    MyFirstScreen:

<SelectableLabel>:
    canvas.before:
        Color:
            rgba: (0, 0, 1, 1) if self.selected else (1, 1, 1, 1)
        Rectangle:
            pos: self.pos
            size: self.size
<RecycleViewWidget>:
    viewclass: 'SelectableLabel'
    SelectableRecycleBoxLayout:
        default_size: None, dp(56)
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'

<MyFirstScreen>:
    name: 'system_setup_page'
    system_name_text_input_id:system_name_text_input_id
    GridLayout:
        cols: 2
        BoxLayout:
            cols: 1
            padding: 20
            RecycleViewWidget:
        FloatLayout:
            Label:
                size_hint: None, None
                text: "Name:"
                font_size: 22
                pos_hint: {'center': (20/100, 90/100)}
            TextInput:
                id: system_name_text_input_id
                size_hint: None, None
                hint_text: "Type Your Name..."
                size: 200, 30
                multiline: False
                pos_hint: {'center': (65/100, 90/100)}
                on_text: root.get_text_inputs()
            Label:
                size_hint: None, None
                text: "User ID:"
                font_size: 20
                pos_hint: {'center': (20/100, 70/100)}
            TextInput:
                size_hint: None, None
                size: 200, 30
                hint_text: "Type Your ID..."
                pos_hint: {'center': (65/100, 70/100)}

问题是因为在 update_text_inputs() 中使用 MyFirstScreen() 您创建了 class MyFirstScreen 的新实例,但您必须使用现有实例。

这应该是更好的获取方式,但目前我唯一的想法是为此使用 parent

因为这些元素之间有很多小部件所以需要很多parent:

    my_text_input = self.parent.parent.parent.parent.parent.system_name_text_input_id  

我使用 print(self.parent)、下一个 print(self.parent.parent) 等找到它


def update_text_inputs(self, *kwarg):
    #print('parent:', self.parent.parent.parent.parent.parent.system_name_text_input_id)
    #print('parent:', self.parent.parent.parent.parent.parent.system_name_text_input_id.text)

    my_text_input = self.parent.parent.parent.parent.parent.system_name_text_input_id 

    print("my_print_val is:", my_text_input.text)

    my_text_input.text = "Updated Value"