2013-09-10 5 views
0

Я попытался получить доступ к TabbedPanel.content.children [0] и удалить дочерний элемент и переписать новый дочерний элемент, но он не работает. Следует отметить, что TabbedPanel.content является TabbedPanelContent, а не ListView (в моем случае).Изменить содержимое вкладки с помощью кнопки в Kivy

Что я хочу сделать, это отредактировать содержимое моего спискаView. Приложение создает кнопку для создания данных и две вкладки, где первая вкладка создает списокView данных. Если кнопка снова нажата, она удалит предыдущий ListView и введет новый.

Как обновить содержимое вкладки? Код:

#test tabs 

import kivy 
kivy.require('1.0.6') # replace with your current kivy version ! 

from kivy.app import App 
from kivy.uix.button import Button 
from kivy.uix.label import Label 
from kivy.uix.gridlayout import GridLayout 
from kivy.uix.boxlayout import BoxLayout 
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelHeader 
from kivy.properties import ListProperty 
from kivy.properties import DictProperty 
from kivy.uix.listview import ListView, ListItemButton 
from kivy.adapters.dictadapter import DictAdapter 
from kivy.adapters.models import SelectableDataItem 
from kivy.uix.selectableview import SelectableView 
from kivy.uix.listview import ListView, ListItemButton 
from kivy.factory import Factory 
from kivy.lang import Builder 

import random 

#templates kv for SelectableView+BoxLayout called CustomListItem 
Builder.load_string(''' 
[[email protected]+BoxLayout]: 
    size_hint_y: ctx.size_hint_y 
    height: ctx.height 
    ListItemButton: 
     text: ctx.text 
     is_selected: ctx.is_selected 
''') 

class testTabs(BoxLayout): 
    data = ListProperty([1,2,3,4,5]) 

    def __init__(self, *args, **kwargs): 
     super(testTabs, self).__init__(**kwargs) 
     self.listViewDict = {} 
     #layout = GridLayout(rows = 2) 
     self.layout = BoxLayout(orientation = "vertical") 
     #buttonLayout = GridLayout(cols = 4) 
     dataButton = Button(text = "press to load random data to tab 1") 
     dataButton.bind(on_release = self.randData) 
     self.layout.add_widget(dataButton) 

     #create list 
     list_item_args_converter = \ 
       lambda row_index, rec: {'text': rec['text'], 
             'is_selected': rec['is_selected'], 
             'size_hint_y': None, 
             'height': 35} 

     entry_dict = \ 
     {str(i): {'text': str(self.data[i]), 'is_selected': False} \ 
      for i in xrange(len(self.data)) } 

     self.listViewDict = entry_dict 

     sortedDateEntriesList = sorted(self.listViewDict) 
     dict_adapter = DictAdapter(sorted_keys = sortedDateEntriesList, 
            data = self.listViewDict, 
            args_converter=list_item_args_converter, 
            template = 'CustomListItem') 

     self.list_view = ListView(adapter=dict_adapter) 

     ### Create tabs ### 
     self.tabbedPanel = TabbedPanel() 
     self.tabbedPanel.default_tab_text = "data tab" 
     self.tabbedPanel.tab_pos = "top_left" 
     self.tabbedPanel.default_tab_content = self.list_view 

     tabbedPanelHeader = TabbedPanelHeader(text = "tab 2") 
     tabbedPanelHeader.content = Label(text = "Hello world") 

     self.tabbedPanel.add_widget(tabbedPanelHeader) 

     self.layout.add_widget(self.tabbedPanel) 

     self.add_widget(self.layout) 

     #self.tabbedPanel.content.bind(children = self.foo) 

    def foo(self, *args): 
     print "############################in foo args:" 
     print args 
     tabbedPanelHeader = args[0] 
     print tabbedPanelHeader.children 

    def printContent(self, object): 
     print "object:" +str(object) +"'s content: " +str(object.content) 

    def printChildren(self, object): 
     for child in object.children: 
      print "object:" +str(object) +"'s child: " +str(child) 

    #create list view 
    def randData(self, *args): 
     print args 
     self.tabbedPanel.content.children[0].remove_widget(self.list_view) 
     print "content tabbedPanel children:" 
     print self.tabbedPanel.content.children 

     tempData = [] 
     numValues = random.randint(10,20)-1 
     for i in xrange(numValues): 
      tempData.append(random.randint(1,30)) 
     self.data = tempData 

     list_item_args_converter = \ 
       lambda row_index, rec: {'text': rec['text'], 
             'is_selected': rec['is_selected'], 
             'size_hint_y': None, 
             'height': 35} 

     entry_dict = \ 
     {str(i): {'text': str(self.data[i]), 'is_selected': False} \ 
      for i in xrange(len(self.data)) } 

     self.listViewDict = entry_dict 

     sortedDateEntriesList = sorted(self.listViewDict) 
     dict_adapter = DictAdapter(sorted_keys = sortedDateEntriesList, 
            data = self.listViewDict, 
            args_converter=list_item_args_converter, 
            template = 'CustomListItem') 

     self.list_view = ListView(adapter=dict_adapter) 
     self.tabbedPanel.content.children[0].add_widget(self.list_view) 

    def on_data(self, *args): 
     print "on_data func. Data created:" 
     print args 

class MyApp(App): 

    def build(self): 
     return testTabs() 

if __name__ == '__main__': 
    MyApp().run() 

ответ

1

Вместо отводом вокруг с tabbedpanel.content, вы можете просто сохранить ссылку на ваш ListView (или что-нибудь еще вы положили туда) и изменить его позже.

Например, в этом примере вы сохраняете список как self.list_view. Это означает, что у вас может быть метод, который создает новый адаптер, а затем просто заменяет старый, чтобы обновить список. Вы также можете делать такие вещи, как модифицировать data оригинального адаптера по той же ссылке.

Некоторый (непроверенный) пример код будет что-то вроде:

def my_update_method(self, *args): 

    new_dict_adapter = DictAdapter(data = whatever 
            # Obviously you have to make thi 
            args_converter = list_item_args_converter 
            # You have to make this too, not included in 
            # the example 
            ) 

    self.list_view.adapter = new_dict_adapter 
+0

Это похоже на работу с обновлением содержимого ListView (решает эту проблему, но вводит еще один), но в инициализации FUNC я начинаю с 5 пунктов и созданного самостоятельно. list_view настроен на такой размер, я думаю. Поэтому, если есть много элементов, он не сможет прокрутить до конца списка. Я думал о редактировании свойства ListView.row_height, но не знаю формулы. Кто-нибудь знает, как я могу это сделать? Другим решением было бы создать новый ListView каждый раз и изменить содержимое tabbedPanel, так что мы снова вернемся к той же проблеме – lirre

+0

Ах, поэтому вы имеете в виду, что при обновлении списка с большим количеством элементов вы не можете прокручивать до конца, потому что это замки на первоначальной высоте? Я думаю, что это активная ошибка со списком (она уже давно), которая уже может быть исправлена ​​в kivy master, или скоро будет, если нет. Какую версию ты используешь? – inclement

+0

Да, это почти правильно. Я думаю, что ListView имеет некоторый параметр высоты, например scrollHeight или что-то (возможно, ListView.row_height), которое он устанавливает на основе количества элементов, которые у меня есть в ListView (в этом случае 5). Поэтому, когда я генерирую более 15 предметов, он останавливается на 15 элементах. Можно прокручивать больше и просматривать еще несколько предметов, но затем он возвращается к просмотру 15 предметов при остановке анимации прокрутки. Я использую версию Kivy 1.7.2 для окон. – lirre

1

Вы, кажется, хотите изменить данные, приведенные в ListView, вы не должны менять тэ всего ListView для этого. Посмотрите здесь https://github.com/kivy/kivy/issues/1321 это упоминает обходное решение до тех пор, пока ветка data_changed для listview не будет объединена в master. Просто добавьте это в свой kv ::

<ListView>: 
    on_adapter: self.adapter.bind_triggers_to_view(self._trigger_reset_populate) 

Просто обновите данные после этого, покажите свои изменения в списке.

Для вашего вопроса с TabbedPanel все, что вам нужно сделать, это ::

self.tabbedPanel.clear_widgets() 
self.tabbedPanel.add_widget(self.list_view) 

При добавлении виджета на панель с закладками, он фактически добавляет его в область содержимого. Аналогично clear_widgets() очищает область содержимого.

Вы также могли бы сделать ::

self.tabbedPanel.default_tab.content = self.list_view 
self.tabbedPanel.switch_to(self.tabbedPanel.default_tab) 

Это лучше, так как связанный контент обновляется и, таким образом, каждый раз, когда вы меняете на соответствующую вкладку изменилось будет отображаться содержимое.

Соответствующая документация в документации ::

Tabs and content can be removed in several ways: 

    tp.remove_widget(Widget/TabbedPanelHeader) 
or 
    tp.clear_widgets() # to clear all the widgets in the content area 
or 
    tp.clear_tabs() # to remove the TabbedPanelHeaders 

Warning 

To access the children of the tabbed panel, use content.children: 

    tp.content.children 

To access the list of tabs: 

tp.tab_list 
Смежные вопросы