Declaring new widgets with param.Parameterized and use decorators

Hello,

I am looking for a way to declare a custom widget with param.Parameterized and then leverage the full decorator capabilities in the classes that instantiate my widget. Something like this:

class MyWidget(param.Parameterized): 
    button = pn.widgets.Button(name="some button")
    some_value = 1
    
    @param.depends('button.value')
    def update_value(self):
        self.value += 1

    def view(self):
        return pn.Row(self.button)

Then use the widget in other classes/apps in the same way as built in widgets by leveraging decorators. Something like this:

class BigApp(param.Parameterized):
     custom_widget = MyWidget()
    
     @param.depends('custom_widget.value`, watch=True)
     def print_value(self):
         print("value has changed in the custom widget")

     def view(self):
         return pn.Row(self.custom_widget.view())

A design that does accomplish this to a certain extent is by passing the callable from the parent class to the custom widget class, but decorator would be much nicer IMO.

Does any of the panel gurus know how to accomplish this?

Many thanks!

Ogi

I don’t it’s good practice to define widgets like you would define params (or at least it’s not supported at the moment Parameterized objects (e.g. Panel Widgets) as class attributes · Issue #832 · holoviz/param · GitHub)

Instead, you can define params like this:

import panel as pn
import param

pn.extension()


class MyWidget(param.Parameterized):

    button_event = param.Event()
    value = param.Integer(default=0)

    def __init__(self, **params):
        super().__init__(**params)
        self.button = pn.widgets.Button.from_param(self.param.button_event)
        self.value_pane = pn.widgets.IntInput.from_param(self.param.value)

    @param.depends("button_event", watch=True)
    def update_value(self):
        self.value += 1

    def view(self):
        return pn.Row(self.button, self.value_pane)


class BigApp(param.Parameterized):

    custom_widget = param.ClassSelector(class_=MyWidget, default=MyWidget())

    @param.depends("custom_widget.value", watch=True)
    def print_value(self):
        print("value has changed in the custom widget")

    def view(self):
        return pn.Row(self.custom_widget.view())


BigApp(custom_widget=MyWidget(value=3)).view()

1 Like