Forum Archive

Subclassing ui.ListDataSource dealing with events

Phuket2

The below code should be so simple. But it's been sometime since I have done it. I feel I am am right in what I have done, but history tells me, I am normally wrong. The docs say you can set a ui.ListDataSource item as the delegate to a TableView. Which is what I have done. But I am not getting called back. Ok, I have subclassed ui.ListDataSource, but from what I can see it should work. @omz sorry to ask, but am I just doing something stupid or is it broken?

Edit: had to edit, otherwise I would be having coding nightmares of @ccc tracking me down in Pokemon and capturing me 😱😱

import ui, editor

'''
    Pythonista Forum - @Phuket2
'''

def dataset(nb=12, acc_type = 'detail_button'):
    # stupid helper test func.
    # make a list of dicts for ui.ListDataSource
    # no list[dict] comprehension. This is clearer for this purpose
    lst = []
    for i in range(1, nb+1):
        d = dict(title = str(i),
                    image= 'None',
                    accessory_type = acc_type)
        lst.append(d)
    return lst

class MyData(ui.ListDataSource):
    def __init__(self, items = None, *args, **kwargs):
        items = items or [] # edited 
        super().__init__(items, *args, **kwargs)
        self.items = dataset()

    # as far as i can tell, given this is the delegate if should be,
    # called. But its not called when a different row is selected. 
    # the same with other callbacks.
    def action(self, sender):
        print('in action')

    def accessory_action(self, sender):
        print('in accessory_action')

class MyClass(ui.View):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.tbl = None
        self.make_view()

    def make_view(self):
        self.tbl = ui.TableView(name = 'table', frame = self.bounds)
        self.tbl.flex = 'wh'
        ds = MyData()
        self.tbl.data_source = ds
        self.tbl.delegate = ds
        self.add_subview(self.tbl)

if __name__ == '__main__':
    _use_theme = True
    w, h = 300, 400
    f = (0, 0, w, h)

    mc = MyClass(frame=f, bg_color='white', name ='I am Broken 😱')

    if not _use_theme:
        mc.present('sheet', animated=False)
    else:
        editor.present_themed(mc, theme_name='Oceanic', style='sheet', animated=False)
ccc

My "pull request"...

import editor, ui

'''
    Pythonista Forum - @Phuket2, @ccc
'''


def dataset(nb=12, acc_type='detail_button'):
    return [{'title': str(i+1), 'accessory_type': acc_type} for i in range(nb)]


class MyData(ui.ListDataSource):
    def __init__(self, items=None, *args, **kwargs):
        super().__init__(items or [], *args, **kwargs)
        self.items = dataset()
        self.action = self._action
        self.accessory_action = self._accessory_action

    def _action(self, sender):
        assert self is sender, 'Just a curious fact.'
        item = sender.items[sender.selected_row]
        print('in action {title}'.format(**item))

    def _accessory_action(self, sender):
        assert self is sender, 'Just a curious fact.'
        item = sender.items[sender.tapped_accessory_row]
        print('in accessory_action {title}'.format(**item))


class MyClass(ui.View):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.add_subview(self.make_table())

    def make_table(self):
        table = ui.TableView(name='table', frame=self.bounds)
        table.flex = 'wh'
        table.data_source = table.delegate = MyData()
        return table


if __name__ == '__main__':
    _use_theme = True
    frame = (0, 0, 300, 400)
    mc = MyClass(frame=frame, bg_color='white', name='I am NOT Broken 😱')
    if _use_theme:
        editor.present_themed(mc, theme_name='Oceanic', style='sheet',
                              animated=False)
    else:
        mc.present('sheet', animated=False)
abcabc

@Phuket2 ideally your code should have worked. I think that it is a bug in pythonista. The attribute "action" seems to be initialized like
this

        self.action = None

instead of

      self.action = self.action if hasattr(self, 'action') else None
Phuket2

Thanks guys for the workaround and the explanation. I will add a bug report.