Kivy:在kv中绑定回调到SimpleListAdapter
我正在尝试做一些和Kivy Listview示例非常相似的事情——我使用Builder和kv来创建一个ListView,并用文本文件中的行来填充它。我的问题是,我不知道怎么绑定一个回调函数,这样我就可以把选中的行的文本移动到一个列表框里。我的代码是:
from kivy.uix.listview import ListView, ListItemButton
from kivy.uix.gridlayout import GridLayout
from kivy.uix.modalview import ModalView
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
Builder.load_string("""
#:import label kivy.uix.label
#:import sla kivy.adapters.simplelistadapter
<ListViewModal>:
size_hint: None, None
size: 400, 400
ListView:
id: listview_modal
#on_selection_change: callback # <==== attempt #1
size_hint: .8, .8
adapter:
sla.SimpleListAdapter(
data=[s.strip() for s in open('/Users/zen/Dropbox/todo/todo.txt').readlines()],
cls=label.Label,
selection_mode='single',
allow_empty_selection=True)
#on_selection_change: callback # <===== attempt #2
""")
class ListViewModal(ModalView):
def __init__(self, **kwargs):
super(ListViewModal, self).__init__(**kwargs)
class MainView(GridLayout):
'''Implementation of a simple list view that reads data from a file.
'''
def __init__(self, **kwargs):
kwargs['cols'] = 2
super(MainView, self).__init__(**kwargs)
self.listview_modal = ListViewModal()
self.add_widget(self.listview_modal)
text_input = TextInput()
self.add_widget(text_input)
def callback(self, adapter):
self.text_input.text = adapter.selection.text
if __name__ == '__main__':
from kivy.base import runTouchApp
runTouchApp(MainView(width=800))
我还尝试了各种组合,添加ID和属性,以便能够在MainView类中访问适配器,但都没有成功。
任何建议都将非常感谢!
1 个回答
0
第一个问题是你在使用 SimpleListAdapter
,这个适配器之所以叫“简单”,是因为它不支持选择功能。你应该使用普通的 ListAdapter
。另外,你还需要使用 ListItemButton
来支持选择功能。on_selection_change
这个事件必须从 Python 代码中绑定,而不是用 kv 语言,否则它就无法正常工作。最后,你在使用 text_input
这个组件时也遇到了一些问题,想从 adapter.selection
中获取 text
,但要注意,adapter.selection
是一个列表,而不是一个组件。
我已经更新了你的代码,并在我的修改处添加了注释。
Builder.load_string("""
#:import ListItemButton kivy.uix.listview.ListItemButton
#:import la kivy.adapters.listadapter
<ListViewModal>:
size_hint: None, None
size: 400, 400
ListView:
id: listview_modal
size_hint: .8, .8
adapter:
la.ListAdapter(
data=[s.strip() for s in open('/Users/zen/Dropbox/todo/todo.txt').readlines()],
cls=ListItemButton, ### use ListItemButton instead of Label
selection_mode='single',
allow_empty_selection=True)
""")
class ListViewModal(ModalView):
def __init__(self, **kwargs):
super(ListViewModal, self).__init__(**kwargs)
### Bind to `on_selection_change` here in `__init__`
self.ids['listview_modal'].adapter.bind(on_selection_change=self.callback)
### in `__init__`, we don't have a parent yet, so we proxy the callback
def callback(self, adapter):
return self.parent.callback(adapter)
class MainView(GridLayout):
'''Implementation of a simple list view that reads data from a file.
'''
def __init__(self, **kwargs):
kwargs['cols'] = 2
super(MainView, self).__init__(**kwargs)
self.listview_modal = ListViewModal()
self.add_widget(self.listview_modal)
self.text_input = TextInput() ### use `self.text_input` instead of `text_input`
self.add_widget(self.text_input)
def callback(self, adapter):
self.text_input.text = adapter.selection[0].text ### get `text` from the first selected item