1

我正在尝试对列表视图中的字典列表进行排序。我将通过更改 ListAdapter.data 来解决这个问题。

在 kv 文件中,列表视图上方的微调器按钮选择排序值,并且 on_release 调用 root.beer_sort 来更改 ListAdapter(名为 beer_la)数据。将 beer_la.data 打印到控制台,看起来好像变了,但是 App 的显示顺序没有更新。

class CellarDoor(BoxLayout):
    def __init__(self, **kwargs):
        self.beer_archive = []
        self.wine_archive = []
        with open(join(FILE_ROOT, 'beer_archive.csv'), 'rb', 1) as beer_csv:
            self.beer_archive = list(csv.DictReader(beer_csv))

        self.beer_la = ListAdapter(data=self.beer_archive, 
                          args_converter=self.beer_formatter,
                          cls=CompositeListItem,         
                          selection_mode='single',
                          allow_empty_selection=True)
        super(CellarDoor, self).__init__(**kwargs)

    def beer_formatter(self, row_index, beer_data):
        return {'text': beer_data['Beer'],
                'size_hint_y': None,
                'height': 50,
                'cls_dicts': [{'cls': ListItemImage,
                               'kwargs': {'size_hint_x': .2,
                                          'size': self.parent.size,
                                          'cellar': 'Beer',
                                          'style': beer_data['Style']}},
                              {'cls': ListItemLabel,
                               'kwargs': {'text': beer_data['Beer']}},
                              {'cls': ListItemButton,
                               'kwargs': {'text': str(beer_data['Stock'])}}]}

    def beer_sort(self, sort, reverse):
        self.beer_la.data = sorted(self.beer_archive,
                                   key=lambda k: k[sort],
                                   reverse=reverse)
        print "new sort = %s" % sort
        print self.beer_la.data

kv文件的相关部分

<CellarDoor>
    ...
    Spinner:
        id: beer_sort_spinner
        text: 'Brewery'
        values: ['Brewery', 'Beer', 'Year', 'Style', 'Stock', 'Rating', 'Price']
        on_release: root.beer_sort(self.text, (True if future_search_button.state=='down' else False))
    ToggleButton:
        id: future_search_button
        text: 'Reverse'
    Button:
        text: 'Add Beer'
    ListView:
        adapter: root.beer_la
4

3 回答 3

1

我希望我能对你的问题有所帮助。我发现如果我在调用CellarDoor(而不是使用 Kivy 语言)的构造函数之后添加列表视图,那么该sort方法就会开始工作。我的示例是您的简化版本,但您描述的行为仍然存在。

如果您取消注释:

#    ListView:
#        adapter: root.beer_la

并评论:

        self.add_widget(ListView(adapter=self.beer_la))

然后,就像您描述的那样,排序停止工作。

奇怪的是,如果我有一个很大的列表(比如说 100 个),那么ListView在对其执行和操作(滚动或选择)和 item 之后会更新。不知何故,这意味着适配器的属性未绑定到更新屏幕。这可能是一个值得在Github中向开发人员报告的问题。我无法更好地解释你,但我希望它至少能解决你的问题。您可能还想尝试直接在 Kivy Language 中创建和添加适配器

from kivy.adapters.listadapter import ListAdapter
from kivy.uix.listview import ListView, ListItemButton
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.app import App

Builder.load_string("""
<CellarDoor>:
    ToggleButton:
        text: 'Reverse'
        on_state: root.beer_sort((True if self.state=='down' else False))
#    ListView:
#        adapter: root.beer_la
""")

class CellarDoor(BoxLayout):
    def __init__(self, **kwargs):
        self.beer_archive = ["Item #{0}".format(i) for i in range(10)]
        self.beer_la = ListAdapter(data=self.beer_archive, 
                          cls=ListItemButton,
                          selection_mode='single',
                          allow_empty_selection=True)

        super(CellarDoor, self).__init__(**kwargs)
        self.add_widget(ListView(adapter=self.beer_la))


    def beer_sort(self, reverse):
        self.beer_la.data = sorted(self.beer_archive,
                                   reverse=reverse)
        print self.beer_la.data

class TestApp(App):
    def build(self):
        return CellarDoor()

if __name__ == '__main__':
    TestApp().run()
于 2013-07-17T02:29:14.473 回答
0

也许这可以帮助有同样问题的人......

当向 ListView 添加新元素不会更新列表时,我遇到了类似的问题。更新时再次设置数据属性(如上所述)实际上并没有为我解决(Kivy 1.8.0)。

在 Kivy Google Groups 的某个地方,展示了使用 ListViews .populate() 方法的解决方案。

def update_data(self):
  self.list_adapter.data = mydata
  self.list_view.populate()

此方法的问题之一是,在创建 ListView 后,.populate() 属性似乎并不直接存在。所以你必须在调用它之前检查属性是否存在:

def update_data(self):
  self.list_adapter.data = mydata
  if(hasattr(self.list_view, 'populate')):
    self.list_view.populate()

这实际上解决了,但不幸的是列表底部的新项目是可见的,但您无法向下滚动到这些项目。

在挖掘了 ListView 的源代码后,我遇到了 ._reset_spopulate() 方法,它似乎完全符合我的要求:

def update_data(self):
  self.list_adapter.data = mydata
  if(hasattr(self.list_view, '_reset_spopulate')):
    self.list_view._reset_spopulate()

底部的新项目已正确添加,滚动也有效。不要问我为什么这确实有效,也不要指望它在 Kivy 的未来版本中有效。

于 2014-03-24T21:29:34.040 回答
0

在 O'Reilly 的“在 Kivy 中创建应用程序”一书中,它建议了以下_trigger_reset_populate()功能:

    def update_data(self):
        self.list_adapter.data = mydata
        self.list_view._trigger_reset_populate()
于 2017-01-06T03:24:10.363 回答