In this lecture we will discuss widget events, such as button clicks!
from __future__ import print_function
The Button
is not used to represent a data type. Instead the button widget is used to handle mouse clicks. The on_click
method of the Button
can be used to register function to be called when the button is clicked. The doc string of the on_click
can be seen below.
import ipywidgets as widgets
print(widgets.Button.on_click.__doc__)
Register a callback to execute when the button is clicked. The callback will be called with one argument, the clicked button widget instance. Parameters ---------- remove : bool (optional) Set to true to remove the callback from the list of callbacks.
Since button clicks are stateless, they are transmitted from the front-end to the back-end using custom messages. By using the on_click
method, a button that prints a message when it has been clicked is shown below.
from IPython.display import display
button = widgets.Button(description="Click Me!")
display(button)
def on_button_clicked(b):
print("Button clicked.")
button.on_click(on_button_clicked)
Button clicked. Button clicked. Button clicked. Button clicked. Button clicked. Button clicked.
The Text
widget also has a special on_submit
event. The on_submit
event fires when the user hits return.
text = widgets.Text()
display(text)
def handle_submit(sender):
print(text.value)
text.on_submit(handle_submit)
hello press enter
Widget properties are IPython traitlets and traitlets are eventful. To handle changes, the on_trait_change
method of the widget can be used to register a callback. The doc string for on_trait_change
can be seen below.
print(widgets.Widget.on_trait_change.__doc__)
Setup a handler to be called when a trait changes. This is used to setup dynamic notifications of trait changes. Static handlers can be created by creating methods on a HasTraits subclass with the naming convention '_[traitname]_changed'. Thus, to create static handler for the trait 'a', create the method _a_changed(self, name, old, new) (fewer arguments can be used, see below). Parameters ---------- handler : callable A callable that is called when a trait changes. Its signature can be handler(), handler(name), handler(name, new) or handler(name, old, new). name : list, str, None If None, the handler will apply to all traits. If a list of str, handler will apply to all names in the list. If a str, the handler will apply just to that name. remove : bool If False (the default), then install the handler. If True then unintall it.
Mentioned in the doc string, the callback registered can have 4 possible signatures:
Using this method, an example of how to output an IntSlider
's value as it is changed can be seen below.
int_range = widgets.IntSlider()
display(int_range)
def on_value_change(name, value):
print(value)
int_range.on_trait_change(on_value_change, 'value')
Often, you may want to simply link widget attributes together. Synchronization of attributes can be done in a simpler way than by using bare traitlets events.
The first method is to use the link
and dlink
functions from the traitlets
module.
import traitlets
# Create Caption
caption = widgets.Label(value = 'The values of slider1 and slider2 are synchronized')
# Create IntSlider
slider1 = widgets.IntSlider(description='Slider 1')
slider2 = widgets.IntSlider(description='Slider 2')
# Use trailets to link
l = traitlets.link((slider1, 'value'), (slider2, 'value'))
# Display!
display(caption, slider1, slider2)
# Create Caption
caption = widgets.Label(value = 'Changes in source values are reflected in target1')
# Create Sliders
source = widgets.IntSlider(description='Source')
target1 = widgets.IntSlider(description='Target 1')
# Use dlink
dl = traitlets.dlink((source, 'value'), (target1, 'value'))
display(caption, source, target1)
Function traitlets.link
and traitlets.dlink
return a Link
or DLink
object. The link can be broken by calling the unlink
method.
# May get an error depending on order of cells being run!
l.unlink()
dl.unlink()
When synchronizing traitlets attributes, you may experience a lag because of the latency due to the roundtrip to the server side. You can also directly link widget attributes in the browser using the link widgets, in either a unidirectional or a bidirectional fashion.
# NO LAG VERSION
caption = widgets.Label(value = 'The values of range1 and range2 are synchronized')
range1 = widgets.IntSlider(description='Range 1')
range2 = widgets.IntSlider(description='Range 2')
l = widgets.jslink((range1, 'value'), (range2, 'value'))
display(caption, range1, range2)
# NO LAG VERSION
caption = widgets.Label(value = 'Changes in source_range values are reflected in target_range1')
source_range = widgets.IntSlider(description='Source range')
target_range1 = widgets.IntSlider(description='Target range ')
dl = widgets.jsdlink((source_range, 'value'), (target_range1, 'value'))
display(caption, source_range, target_range1)
Function widgets.jslink
returns a Link
widget. The link can be broken by calling the unlink
method.
l.unlink()
dl.unlink()
You should now feel comfortable linking Widget events!