Dynamic number of widgets / params

OK I’m now doing this, I’m not sure if this is ‘correct’ but it works and I’m quite pleased with it. Turned out not to be that difficult.


class Colors(param.Parameterized):
    num = param.Number(3, bounds=(0, None))
    colors = param.List([])
    color_defaults = ['#1930e0', '#eded0e', '#cc0c49']
    
    def __init__(self, **param):
        super(Colors, self).__init__(**param)
        
        self.colors_col = pn.Column()
        for _ in range(self.num):
            self._add_color()
    
        self.param.watch(self.color_callback, ['colors'])
    
    
    def _add_color(self):
        try:
            default = self.color_defaults[len(self.colors_col)]
        except IndexError:
            default = '#FFFFFF'
            
        self.colors.append(default)
        widget = pn.widgets.ColorPicker(value=default)
        self.colors_col.append(widget)
        widget.param.watch(self.color_event, ['value'])
        
    def _remove_color(self):
        widget = self.colors_col.pop(-1)
        self.colors.pop(-1)
        [widget.param.unwatch(watcher) for watcher in widget.param._watchers]
        del widget
    
    @param.depends('num', watch=True)
    def _update_colors(self):
        while len(self.colors_col) != self.num:
            if len(self.colors_col) > self.num:
                self._remove_color()
            elif len(self.colors_col) < self.num:
                self._add_color()
        self.param.trigger('colors')

    def color_event(self, *events):
        for event in events:
            idx = list(self.colors_col).index(event.obj)
            self.colors[idx] = event.new
        self.param.trigger('colors')
        print(self.colors)
                
    def panel(self):
        return pn.Column(pn.Param(self.param), self.colors_col)
                 
        
    def color_callback(self, events):     
        print(events)
                    
c = Colors()
c.panel().servable()

I’ve tried to obliviate the widget that gets removed but not very successfully, if i make a weakref to the widget that still persists.

EDIT: Added a color list that holds the colors. I trigger it manually because assigning elements doenst trigger it. It works well but the field showing the value of the list doesnt uptake (although I dont need this atm)

1 Like