【问题标题】:Change contents of a tab from a button in Kivy从 Kivy 中的按钮更改选项卡的内容
【发布时间】:2013-09-10 07:38:29
【问题描述】:

我尝试访问 TabbedPanel.content.children[0] 并删除孩子并重新创建一个新孩子,但它不起作用。请注意,TabbedPanel.content 是 TabbedPanelContent 而不是 ListView(在我的情况下)。

我想要做的是编辑我的 listView 的内容。该应用程序创建一个按钮来生成数据和两个选项卡,其中第一个选项卡创建数据的 listView。如果再次按下按钮,它将删除以前的 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('''
[CustomListItem@SelectableView+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()

【问题讨论】:

    标签: python tabs kivy


    【解决方案1】:

    您似乎想要更改提供给列表视图的数据,您不必为此更改整个列表视图。看这里https://github.com/kivy/kivy/issues/1321 这提到了一种解决方法,直到 listview 的 data_changed 分支合并到 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)
    

    这会更好,因为链接的内容会更新,因此每次更改选项卡时都会显示相应的更改内容。

    docs中的相关文档::

    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
    

    【讨论】:

      【解决方案2】:

      您可以只保留对您的列表视图(或您放入其中的任何其他内容)的引用,然后再对其进行修改。

      例如,在本例中,您将列表视图存储为 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
      

      【讨论】:

      • 它似乎可以更新 ListView 内容(解决了问题但引入了另一个),但是在 init func 中我从 5 个项目开始,并且创建的 self.list_view 被调整到我认为的大小。因此,如果有很多项目,它将无法滚动到列表的末尾。我想编辑 ListView.row_height 属性但不知道公式。有谁知道我该如何调整它?另一种解决方案是每次创建一个新的 ListView 并修改 tabbedPanel 的内容,所以我们又回到了同样的问题
      • 啊,所以您的意思是当您使用更多项目更新列表视图时,您无法滚动到最后,因为它锁定在原始高度?我认为这是 listview 的一个活跃错误(已经存在很长时间),可能已经在 kivy master 中修复,或者如果没有,很快就会修复。你用的是什么版本?
      • 是的,这几乎是正确的。我认为 ListView 有一些高度参数,如 scrollHeight 或其他东西(可能是 ListView.row_height),它根据我在 ListView 中拥有的项目数(在本例中为 5)设置。因此,当我生成超过 15 个项目时,它会停止在 15 个项目。可以滚动更多并查看更多项目,但随后它会在滚动动画停止时返回查看 15 个项目。我在 windows 上使用 Kivy 1.7.2 版。
      • 在这种情况下,您可以通过从 git 升级到最新的 kivy 来修复它(尽管我不知道这在 Windows 上是否很难),因为最近在该区域进行了一些工作这可能已经修复了这个错误。除此之外,正如您在上面建议的那样,您可以尝试替换小部件 - 您可以使用 parent = self.list_view.parent then do parent.remove_widget(self.list_view)` 获取其父级并创建+添加一个新的列表视图。这可能会奏效,尽管它不是理想的解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-01
      • 2015-05-24
      • 1970-01-01
      • 2012-02-16
      相关资源
      最近更新 更多