ipywidgets icon indicating copy to clipboard operation
ipywidgets copied to clipboard

bug: selected_index of Tab widget after changing children and setting selected_index incorrect

Open mariobuikhuizen opened this issue 4 years ago • 4 comments

After changing the children and setting the selected_index attribute to the value it had before, selected_index is set to 0.

tab

Code to reproduce:

import ipywidgets

tabs = ipywidgets.Tab()
tabs.children = [ipywidgets.Label(value='tab1'), ipywidgets.Label(value='tab2')]
tabs.observe(lambda change: print(f"selected index: {change['new']}") , names='selected_index')

def change_children(_):
    tabs.children = [ipywidgets.Label(value='tab1'), ipywidgets.Label(value='tab2')]
    tabs.selected_index = 1

btn = ipywidgets.Button(description='change_children')
btn.on_click(change_children)

ipywidgets.VBox([tabs, btn])

mariobuikhuizen avatar Oct 02 '20 15:10 mariobuikhuizen

@mariobuikhuizen did you find any sort of workaround for this issue? I am experiencing something similar.

sohailsomani avatar Apr 19 '21 02:04 sohailsomani

Hi,

Same thing for me ... but I've found a workaround ;) ! Before changing the children attribute, you should reset the selected_index with : tabs.selected_index = None

I put the modified example below.

import ipywidgets

tabs = ipywidgets.Tab()
tabs.children = [ipywidgets.Label(value='tab1'), ipywidgets.Label(value='tab2'), ipywidgets.Label(value='tab3'), ipywidgets.Label(value='tab4')]
tabs.observe(lambda change: print(f"selected index: {change['new']}") , names='selected_index')

def change_children(_):
    id = tabs.selected_index
    tabs.selected_index = None   # Warning : this will emit a change event
    tabs.children = [ipywidgets.Label(value='tab1'), ipywidgets.Label(value='tab2'), ipywidgets.Label(value='tab3'), ipywidgets.Label(value='tab4')]
    tabs.selected_index = id

btn = ipywidgets.Button(description='change_children')
btn.on_click(change_children)

ipywidgets.VBox([tabs, btn])

ph-pi avatar Apr 29 '21 22:04 ph-pi

I also came across this issue, but I have the additional complication that I want to set tabs.children from an observer to selected_index. This would result in an infinite recursion in @ph-pi 's workaround. My use case is to wrap Tabs into something where only a limited number of tabs is displayed and the active tab is always the middle tab (imagine the tabs being on turnable wheel). Any input on how to achieve this is

dokempf avatar Mar 02 '22 14:03 dokempf

One pattern to break an infinite loop is to create a variable that both observers can see, and in one observer set the variable, do the change which triggers the other observer, then reset the variable back. In the other observer, check the value of that variable before deciding what to do. Essentially, the variable is a way for the two observers to communicate about what they are currently doing.

jasongrout avatar Mar 02 '22 16:03 jasongrout