Reputation: 123
I am trying to get an ipywidget button to change colour when clicked. I figured a way to do it as below
import ipywidgets as ipw
from ipywidgets import *
from IPython.display import display, HTML, clear_output
from IPython.display import display, HTML
pdf_btn = ipw.Button(description = 'Run PDF',button_style = 'danger',
layout=Layout(width='150px', height='30px'))
new_btn = ipw.Button(description = 'PDF done',button_style = 'success',
layout=Layout(width='150px', height='30px'))
HBox = ipw.HBox([pdf_btn])
HBox1 = ipw.HBox([new_btn])
def clear(b):
clear_output()
display(HBox1)
pdf_btn.on_click(clear)
display(HBox)
When inputting this code in Jupyter Notebook and rendering through Voila nothing happens.
Any ideas why ? And any suggestions ?
Upvotes: 0
Views: 1004
Reputation: 9790
You can just update the button style maybe? Like so:
import ipywidgets as ipw
from ipywidgets import *
from IPython.display import display, HTML, clear_output
from IPython.display import display, HTML
pdf_btn = ipw.Button(description = 'Run PDF',button_style = 'danger',
layout=Layout(width='150px', height='30px'))
HBox = ipw.HBox([pdf_btn])
def clear(b):
pdf_btn.button_style="success"
pdf_btn.description="PDF done"
pdf_btn.on_click(clear)
display(HBox)
Note that your code fails in JupyterLab.
Voila is much more similar to JupyterLab's rendering machinery than the classic interface. For now, it is best to use JupyterLab in conjunction with developing for Voila. (Note that this will change soon as the underlying machinery for what is now the traditional Jupyter notebook interface will soon run on machinery more in line with JupyterLab, see Build Jupyter Notebook v7 off of JupyterLab components. A lot of the old code / approaches will then consistently not work and either interface will be as suitable for developing with Voila in mind.)
When your code fails in JupyterLab it logs that to the console, similar to as shown here. I suspect you could follow Jason's advice, what I reference in my reply, which is here, if you actually want the other button there. (I guess I should say if you actually want the other HBox there since for some reason you have each button in a separate HBox in your code.) In other words, you'd need to add in how to handle the output from HBox1 correctly as part of the main output. Yours is going to the JupyterLab Log console as it is now.
So one option is to add HBox1 in as a displayed item, yet hide it initially:
import ipywidgets as ipw
from ipywidgets import *
from IPython.display import display, HTML, clear_output
from IPython.display import display, HTML
pdf_btn = ipw.Button(description = 'Run PDF',button_style = 'danger',
layout=Layout(width='150px', height='30px'))
new_btn = ipw.Button(description = 'PDF done',button_style = 'success',
layout=Layout(width='150px', height='30px'))
HBox = ipw.HBox([pdf_btn])
HBox1 = ipw.HBox([new_btn])
HBox1.layout.visibility = 'hidden' #based on https://github.com/jupyter-widgets/ipywidgets/issues/674#issuecomment-234321603
def clear(b):
HBox1.layout.visibility = 'visible'
HBox.layout.display = 'none' #based on https://stackoverflow.com/a/54134344/8508004
pdf_btn.on_click(clear)
display(HBox)
display(HBox1)
You could also make an overarching vertical box for the items and then toggle which one it contains, similar to here. This is the 'cleanest' option I'll list here, other than just having one button & changing the button itself:
import ipywidgets as ipw
from ipywidgets import *
from IPython.display import display, HTML, clear_output
from IPython.display import display, HTML
pdf_btn = ipw.Button(description = 'Run PDF',button_style = 'danger',
layout=Layout(width='150px', height='30px'))
new_btn = ipw.Button(description = 'PDF done',button_style = 'success',
layout=Layout(width='150px', height='30px'))
HBox = ipw.HBox([pdf_btn])
HBox1 = ipw.HBox([new_btn])
vb = VBox(children = [HBox])
def clear(b):
vb.children = [HBox1]
pdf_btn.on_click(clear)
display(vb)
('cleanest' in regards to it not creating extra space in the output area.)
Or combine the vertical box approach with the approach of toggling off via the layout settings:
import ipywidgets as ipw
from ipywidgets import *
from IPython.display import display, HTML, clear_output
from IPython.display import display, HTML
pdf_btn = ipw.Button(description = 'Run PDF',button_style = 'danger',
layout=Layout(width='150px', height='30px'))
new_btn = ipw.Button(description = 'PDF done',button_style = 'success',
layout=Layout(width='150px', height='30px'))
HBox = ipw.HBox([pdf_btn])
HBox1 = ipw.HBox([new_btn])
HBox1.layout.visibility = 'hidden' #based on https://github.com/jupyter-widgets/ipywidgets/issues/674#issuecomment-234321603
vb = VBox(children = [HBox, HBox1])
def clear(b):
HBox1.layout.visibility = 'visible'
HBox.layout.display = 'none' #based on https://stackoverflow.com/a/54134344/8508004
pdf_btn.on_click(clear)
display(vb)
And if you want to fully leverage Jupyter's display system further, combine it with an overarching out
so you can use print()
, too:
import ipywidgets as ipw
from ipywidgets import *
from IPython.display import display, HTML, clear_output
from IPython.display import display, HTML
out = widgets.Output()
pdf_btn = ipw.Button(description = 'Run PDF',button_style = 'danger',
layout=Layout(width='150px', height='30px'))
new_btn = ipw.Button(description = 'PDF done',button_style = 'success',
layout=Layout(width='150px', height='30px'))
HBox = ipw.HBox([pdf_btn])
HBox1 = ipw.HBox([new_btn])
vb = VBox(children = [HBox])
def clear(b):
vb.children = [HBox1]
with out:
print('Enjoy!')
pdf_btn.on_click(clear)
with out:
display(vb)
out
Upvotes: 1