How can I update a ListView widget ?

753 views
Skip to first unread message

Nim4n

unread,
Dec 21, 2013, 6:19:53 AM12/21/13
to kivy-...@googlegroups.com
Hi I have a listItemButton and I need to update the content, I try something like this but It dosen't work  and I can't update the content without removing  the widget and adding It . how can I do this?   

 def update_widget(self):
        self.data_items = []
        for i in self.chan_dict:
            self.data_items.append(DataItem(text=self.chan_dict[i].channel, channel=self.chan_dict[i]))

        self.list_item_args_converter = lambda row_index, obj: {'text':obj.text,
                                                           'channel':obj.channel,
                                                           'size_hint_y': None,
                                                           'obj': self.app.Main,
                                                           'twisted_obj': self.transport,
                                                           }
        self.list_adapter = ListAdapter(data=self.data_items,
                                   args_converter=self.list_item_args_converter,
                                   selection_mode='single',
                                   propagate_selection_to_data=True,
                                   allow_empty_selection=False,
                                   cls=nimalist,)
        #self.app.Main.remove_widget(self.app.Main.list_view)
        self.app.Main.list_view = ListView(adapter=self.list_adapter)       
        #self.app.Main.add_widget(self.app.Main.list_view)
Message has been deleted

Noob Saibot

unread,
Dec 25, 2013, 2:25:27 PM12/25/13
to kivy-...@googlegroups.com
Questions:
  1. What is "the content"? ListViews separate the "data" from the "view" (what is being displayed).
  2. While using "DataItem" isn't wrong, in the interest of simplicity, is it necessary?
  3. Are you aware that by simply changing your data list, it triggers a re-population of your ListView? Try it.

Nim4n

unread,
Dec 26, 2013, 5:29:33 AM12/26/13
to kivy-...@googlegroups.com
1. I write an Operation Panel for asterisk and the content is live channels and I show them as button in list view. so when some body create a channel or hangup a channel I need to update my list view. 
2. No I see that in document example and I think It is necessary! 
3.I didn't get . what do you mean by simply changing?  I add an empty list  at the end of this function an if you are right I shouldn't see any data in my list view right? but It dosen't worked.

 def update_widget(self):
        self.data_items = []
        for i in self.chan_dict:
            self.data_items.append(DataItem(text=self.chan_dict[i].channel, channel=self.chan_dict[i]))

        self.list_item_args_converter = lambda row_index, obj: {'text':obj.text,
                                                           'channel':obj.channel,
                                                           'size_hint_y': None,
                                                           'obj': self.app.Main,
                                                           'twisted_obj': self.transport,
                                                           }
        self.list_adapter = ListAdapter(data=self.data_items,
                                   args_converter=self.list_item_args_converter,
                                   selection_mode='single',
                                   propagate_selection_to_data=True,
                                   allow_empty_selection=False,
                                   cls=nimalist,)
        self.app.Main.remove_widget(self.app.Main.list_view)
        self.app.Main.list_view = ListView(adapter=self.list_adapter)        
        self.app.Main.add_widget(self.app.Main.list_view)
self.data_items = []

Noob Saibot

unread,
Dec 26, 2013, 7:03:38 PM12/26/13
to kivy-...@googlegroups.com
How is your ListView initially created? Is it with update_widget function?

Nim4n

unread,
Dec 27, 2013, 4:51:16 AM12/27/13
to kivy-...@googlegroups.com


what do you mean? I didn't define any thing special for update I just use this update function

Noob Saibot

unread,
Dec 27, 2013, 12:29:37 PM12/27/13
to kivy-...@googlegroups.com
I mean, is the update_widget function used for first creating the ListView, or just updating the ListView?

Noob Saibot

unread,
Dec 27, 2013, 8:00:21 PM12/27/13
to kivy-...@googlegroups.com
I ask because your `update_widgets` function appears to be CREATING extra `ListAdapter` and `ListView` widgets, instead of UPDATING an existing `ListView` properties. It's not clear what you're trying to do here.
Message has been deleted

Nim4n

unread,
Dec 28, 2013, 12:11:46 AM12/28/13
to kivy-...@googlegroups.com
I try to update my listview and the only way that works for me was this way .


Noob Saibot

unread,
Dec 29, 2013, 2:35:09 PM12/29/13
to kivy-...@googlegroups.com
I don't think it is working for you. What you have here is an "update" function that doesn't update anything. Instead, it creates a new ListViewListAdapter, etc. each time (and without removing the old ones, from what i can tell). You're doing it wrong.

design in .kv, callback in .py.

ALL of your callbacks (i.e., interactions with widgets, touches, changes, etc.) should be written in python. ALL your widgets should be designed/created in kvlang, unless they are part of a callback.

Is this more what you were going for?

class ListViewer(FloatLayout):
    app
= ObjectProperty(None)
    lview
= ObjectProperty(None)
    transport
= ObjectProperty(None)
    data_items
= ListProperty([])
    chan_dict
= DictProperty({}) #I'm Assuming.

   
def _args_converter(self, row_index, obj):
        _dict
= {'channel': obj.channel,
                 
'size_hint_y': None,
                 'obj': self.app.main,
                 
'twisted_obj': self.transport}
       
return _dict

   
def update_widget(self):
       
#self.chan_dict = {...}
       
#self.data_items = []


       
for i in self.chan_dict:
           
self.data_items.append(DataItem(text=self.chan_dict[i].channel, channel=self.chan_dict[i]))


       
# Updating your 'data' will AUTOMATICALLY update your `ListView`

   
def selection_changed(self, *args):
       
print 'You can even bind a callback that does something when your selection changes, if you want.'

class MyApp(App):
    main
= ObjectProperty()

   
def build(self):
        app
= ListViewer()
        app
.update_widget()
       
return app

Builder.load_string("""
#Note: `ListAdapter`s declare differently in kvlang (see
here).

<ListViewer>:
    lview: lview_id
    app: app

    ListView:
        id: lview_id
        pos_hint: {'center_x': 0.5, 'center_y': 0.5}
        size_hint: 0.5, 0.7
        on_selection_change: root.selection_changed(*args)
        adapter:
            ListAdapter(
                data=root.data_items,
                selection_mode='single',
                args_converter=root._args_converter,
                propagate_selection_to_data=True,
                allow_empty_selection=False,
                cls=Nimalist)
"""
)

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

Nim4n

unread,
Jan 5, 2014, 2:53:22 AM1/5/14
to kivy-...@googlegroups.com

tnx for your answer. I know my way is not a good way! but I said i tried other thing like just updating my data_items without removing widget and etc, and nothing worked so I have to remove widget and rebuild It. about your solution I don't understand what is the diffrence between kv languege and python class? as I know there is not any diffrence between them. am I right?

in your way you just update the data_items but I test that(not in kv languege) It didn't work for me

Nim4n

unread,
Jan 5, 2014, 5:26:33 AM1/5/14
to kivy-...@googlegroups.com


I found the solution . the key was dapter.data !

class CustomListView(ListView):
    def __init__(self, **kwargs):
        #self.data_items = kwargs['data_items']
        self.data_items = []




        self.list_item_args_converter = lambda row_index, obj: {'text':obj.text,
                                                           'channel':obj.channel,
                                                           'size_hint_y': None,
                                                           'obj': kwargs['main'],
                                                           'twisted_obj': kwargs['transport'],
                                                           'height': 100,
                                                           }
        self.adapter = ListAdapter(data=self.data_items,

                                   args_converter=self.list_item_args_converter,
                                   selection_mode='single',
                                   propagate_selection_to_data=True,
                                   allow_empty_selection=False,
                                   cls=nimalist,)
        kwargs['adapter']= self.adapter
        super(CustomListView, self).__init__(**kwargs)

                                  
    def update(self, data):
        self.adapter.data = data

Noob Saibot

unread,
Jan 15, 2014, 6:06:25 PM1/15/14
to kivy-...@googlegroups.com
I'm sorry. I just now read your post.
 
"...about your solution I don't understand what is the diffrence between kv languege and python class? as I know there is not any diffrence between them. am I right?"

WRONG!

Kivy was meant to work together with kvlang and python. The best practice is to design in .kv, callback in .py. That means that, as a rule of thumb, the ONLY thing you should be doing in python is callbacks (interactions between widgets, touch events, motion, etc.). Everything else should be done in kvlang. If you're creating new widgets, sizing, adding widgets, with canvas:..., etc. in python and it's NOT part of a callback, you're doing it wrong!

Take this example here:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.uix.ScreenManager import Screen
from kivy.properties import StringProperty, ObjectProperty, BooleanProperty

class FriendWidget(Widget):
    bg_image
= StringProperty('')

class MyWidget(Widget):
    my_friend
= ObjectProperty(None)
    foobar = BooleanProperty(False)

   
def on_foobar(self, *args):
       
if self.foobar:
           
self.my_friend.bg_image = ''

   
def on_touch_down(self, touch):
       
if self.collide_point(*touch.pos):
            self.foobar = not self.foobar
           
return True
       
else:
           
return False

class MyScreen(Screen):
   
pass

kv = """
<FriendWidget>:
    bg_image: 'atlas://data/images/defaulttheme/button_disabled'

    canvas.before:
        BorderImage:
            source: self.bg_image
            size: self.size
            pos: self.pos

<MyWidget>:
    canvas.before:
        BorderImage:
            source:'atlas://data/images/defaulttheme/button'
            size: self.size
            pos: self.pos

<MyScreen>:
    name: 'My Screen'

    FriendWidget:
        id: friend_widget_id
        size_hint: 0.1, 0.1
        pos_hint: {'center_x': 0.25, 'center_y': 0.5}

    MyWidget:
        my_friend: friend_widget_id
        size_hint: 0.1, 0.1
        pos_hint: {'center_x': 0.75, 'center_y': 0.5}

"""


class MyApp(App):

   
def build(self):
       
Builder.load_string(kv)
       
return MyScreen()


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

Only callbacks are in python. The kvlang automatically binds properties, adds widgets, canvases displays, etc. all in one! This separates responsibilities, and makes for better code in all areas. i.e....
  • If your widgets aren't displaying correctly, check the .kv code.
  • If the widgets aren't behaving correctly, check the .py code.
Try doing this in pure python and you'll see how quickly things get messy.

In your "solution" you ended up having to create a global function, that manually goes into the ListView's hidden adapter, just to change the data property, that comes from ANOTHER part of your app. I really suggest you take the time to learn kvlang, and apply the design in .kv, callback in .py principle to your app. It's not as "scary" as people think. TRUST ME. It's not that huge an investment, and well worth it. :-)
Reply all
Reply to author
Forward
0 new messages