我正在尝试在列表视图中对字典列表进行排序。我将通过更改ListAdapter.data来实现它。
在kv文件中,listview上方的微调按钮选择排序值,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
答案 0 :(得分:1)
我希望我能帮你解决一下你的问题。我发现如果在调用CellarDoor
的构造函数(而不是使用Kivy语言)后添加列表视图,则sort
方法开始工作。我的示例是您的简化版本,但您描述的行为仍然存在。
如果您取消注释:
# ListView:
# adapter: root.beer_la
并发表评论:
self.add_widget(ListView(adapter=self.beer_la))
然后,排序就像你描述的那样停止工作。
奇怪的是,如果我有一个大的列表(比方说100),ListView
在对它执行和操作(滚动或选择)和项目后会更新。不知何故,这意味着适配器的属性没有绑定更新屏幕。这可能是一个值得在Github中向开发人员报告的问题。我不能更好地解释你,但我希望至少它能解决你的问题。您可能还想尝试create and add the adapter directly in 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()
答案 1 :(得分:0)
也许这可以帮助有同样问题的人......
在向ListView添加新元素时,我遇到了类似的问题,无法更新列表。 更新时再次设置数据属性(如上所述)实际上对我没有用(Kivy 1.8.0)。
在Kivy Google网上论坛的某个地方,展示了使用ListViews .populate()方法的解决方案。
def update_data(self):
self.list_adapter.data = mydata
self.list_view.populate()
此方法的一个问题是,.populate()属性似乎在创建ListView后不会直接存在。因此,您必须在调用之前检查该属性是否存在:
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中有用。
答案 2 :(得分:0)
在&#34; Creating apps in Kivy&#34;来自O&#39; Reilly的书,它建议了_trigger_reset_populate()
函数:
def update_data(self):
self.list_adapter.data = mydata
self.list_view._trigger_reset_populate()