Kivy:无法更新来自另一个 class 的文本输入值
Kivy: Can't update text input value from another class
我是 kivy
的新手。我正在尝试从另一个 class 更改文本输入值(TextInput
框中显示的字符串值),但没有通过。
我在 class MyFirstScreen
中有以下小部件:
- 一个
RecycleView
有多个项目(每个项目是一个 dictionary
)
- 两个
TextInput
我想做的事情: 当 RecycleView
中的每个项目被选中时,TextInput
s 应该更新并加载所选项目 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"
我是 kivy
的新手。我正在尝试从另一个 class 更改文本输入值(TextInput
框中显示的字符串值),但没有通过。
我在 class MyFirstScreen
中有以下小部件:
- 一个
RecycleView
有多个项目(每个项目是一个dictionary
) - 两个
TextInput
我想做的事情: 当 RecycleView
中的每个项目被选中时,TextInput
s 应该更新并加载所选项目 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"