Wabiloo
Wabiloo

Reputation: 131

Is there a way to bind a widget to a variable so that the widget updates when the variable is changed?

I would like to find a way of binding a widget (TextWidget in this case) to a variable or function. The idea being that as other parts of the code change the variable, the widget is automatically updated to show the content of that variable.

This is what I've done so far to keep the widget displaying the content of an array of integers:

selected = list()

def list_recorded_points():
    return ", ".join([str(i) for i in selected])

def record_point(i):
    selected.append(i)
    t.value = list_recorded_points()

import ipywidgets as widgets
t = widgets.Text(
    value=list_recorded_points(),
    placeholder='Type something',
    description='String:',
    disabled=False
)
t

I do find it quite verbose though, and having to call record_point instead of just being able to change the variable selected makes this less usable...

Upvotes: 2

Views: 1373

Answers (1)

Roman Mkrtchian
Roman Mkrtchian

Reputation: 3006

One classic way to do this is to use traitlets that is already heavily used in ipywidgets.

This solution will not work when adding something to the list, but only when reassigning the whole list. This is because traitlets manages only events on assignement and not on object change. If performance is not important in your use case it may be ok.

You will be able to do s.selected = s.selected + [5] to update the text, but s.selected.append(5) will not update it.


That said, here is how to do it:

You can first create a class inheriting from traitlets.Hastraits, and put your selected variable there as a trait.

import traitlets as tl

class SelectedClass(tl.HasTraits):
    selected = tl.List()

Then you create your text widget and an instance of your SelectedClass:

import ipywidgets as widgets

t = widgets.Text(
    value="",
    placeholder='Type something',
    description='String:',
    disabled=False
)

s = SelectedClass()

And finally you create a directional link from your variable to the value of the widget, with a transformation function.

def transform(selected_list): 
    return ", ".join([str(i) for i in selected_list])

tl.directional_link((s, "selected"), (t, "value"), transform=transform)

Upvotes: 2

Related Questions