Kivy:在kv中绑定回调到SimpleListAdapter

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

我正在尝试做一些和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

撰写回答