在我的Kivy应用中,当on_focus
时,文本输入之一触发DropDown小部件的打开。文本输入是自定义BoxLayout IngredientRow
的一部分,我只需按一下按钮就可以将其输入到屏幕上。
我想要的是用从DropDown中选择的按钮的文本填充textinput。这适用于第一个IngredientRow
。但是,当我添加新行时,从DropDown中选择与第一行不同的行中的一项,将填充第一行中的textinput。参见下面的一个最小的工作示例:
py文件:
from kivy.app import App
from kivy.factory import Factory
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.dropdown import DropDown
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.textinput import TextInput
class DelIngButton(Button):
pass
class DropListButton(Button):
def __init__(self, **kwargs):
super(DropListButton, self).__init__(**kwargs)
self.bind(on_release=lambda x: self.parent.parent.select(self.text))
class IngredientRow(BoxLayout):
pass
class MeasureDropDown(DropDown):
pass
####################################
class AddWindow(Screen):
def __init__(self, **kwargs):
super(AddWindow, self).__init__(**kwargs)
self.DropDown = MeasureDropDown()
def addIngredient(self, instance): #adds a new IngredientRow
row = instance.parent
row.remove_widget(row.children[0])
row.add_widget(Factory.DelIngButton(), index=0)
self.ingsGrid.add_widget(Factory.IngredientRow(), index=0)
class WMan(ScreenManager):
def __init__(self, **kwargs):
super(WMan, self).__init__(**kwargs)
kv = Builder.load_file("ui/layout.kv")
class RecipApp(App):
def build(self):
return kv
if __name__ == "__main__":
RecipApp().run()
和kv文件:
#:set text_color 0,0,0,.8
#:set row_height '35sp'
#:set main_padding ['10sp', '10sp']
#:set small_padding ['5sp', '5sp']
<DropListButton>: # Button for custom DropDown
color: text_color
background_normal: ''
<DelIngButton>: # Button to delete row
text: '-'
size_hint: None, None
height: row_height
width: row_height
on_release: self.parent.parent.remove_widget(self.parent)
<MeasureDropDown>:
id: dropDown
DropListButton:
size_hint: 1, None
height: row_height
text: "g"
DropListButton:
size_hint: 1, None
height: row_height
text: "Kg"
TextInput:
size_hint: 1, None
height: row_height
hint_text: 'new'
<IngredientRow>:
orientation: 'horizontal'
size_hint: 1, None
height: row_height
spacing: '5sp'
TextInput:
id: ing
hint_text: 'Ingredient'
multiline: False
size_hint: .6, None
height: row_height
TextInput:
id: quant
hint_text: 'Quantity'
multiline: False
size_hint: .2, None
height: row_height
TextInput:
id: measure
hint_text: 'measure'
size_hint: .2, None
height: row_height
on_focus:
app.root.ids.add.DropDown.open(self) if self.focus else app.root.ids.add.DropDown.dismiss(self)
app.root.ids.add.DropDown.bind(on_select=lambda self, x: setattr(app.root.ids.add.ingredientRow.children[1], 'text', x))
Button:
id: addIng
text: "+"
size_hint: None, None
height: row_height
width: row_height
on_release: app.root.ids.add.addIngredient(self)
<MainScrollView@ScrollView>:
size_hint: 1, None
scroll_type: ['bars', 'content']
##################
# Windows
##################
WMan:
AddWindow:
id: add
<AddWindow>:
name: 'add'
ingsGrid: ingsGrid
ingredientRow: ingredientRow
MainScrollView:
height: self.parent.size[1]
GridLayout:
cols:1
size_hint: 1, None
pos_hint: {"top": 1}
height: self.minimum_height
padding: main_padding
StackLayout:
id: ingsGrid
size_hint: 1, None
height: self.minimum_height
orientation: 'lr-tb'
padding: small_padding
IngredientRow:
id: ingredientRow
我了解问题出在代码的以下部分:
on_select=lambda self, x: setattr(app.root.ids.add.ingredientRow.children[1], 'text', x)
因为这将始终称为第一个成分行。但是,我不知道如何引用调用DropDown的IngredientRow。
问题是,每次measure
TextInput
获得焦点时,都会将另一个lambda函数添加到on_select
的MeasureDropDown
事件中,并且没有绑定。这意味着每当选择一个下拉选项时,所有这些累积的lambda函数都将被执行,因此,每一个获得关注的TextInput
都会更改其文本。