Kivy:无法从另一个类更新文本输入值

0 投票
1 回答
1002 浏览
提问于 2025-06-18 04:10

我刚开始学习 kivy。我想从另一个类里改变文本输入框的值(也就是在 TextInput 框里显示的字符串),但是没有成功。

class MyFirstScreen 里,我有以下几个组件:

  • 一个 RecycleView,里面有多个项目(每个项目都是一个 dictionary
  • 两个 TextInput 输入框

我想做的事情:当选择 RecycleView 中的每个项目时,TextInput 输入框应该更新,并显示所选项目的 dictionary 中对应的值。

但是当我尝试从另一个类(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)}

相关问题:

  • 暂无相关问题
暂无标签

1 个回答

3

问题出在你在 update_text_inputs() 里使用了 MyFirstScreen(),这样会创建一个新的 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" 

撰写回答