1ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh"""An implementation of tabbed pages using only standard Tkinter. 2ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 3ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehOriginally developed for use in IDLE. Based on tabpage.py. 4ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 5ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehClasses exported: 6ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehTabbedPageSet -- A Tkinter implementation of a tabbed-page widget. 7ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehTabSet -- A widget containing tabs (buttons) in one or more rows. 8ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 9ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh""" 10ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom Tkinter import * 11ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 12ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass InvalidNameError(Exception): pass 13ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass AlreadyExistsError(Exception): pass 14ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 15ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 16ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TabSet(Frame): 17ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """A widget containing tabs (buttons) in one or more rows. 18ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 19ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Only one tab may be selected at a time. 20ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 21ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 22ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __init__(self, page_set, select_command, 23ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tabs=None, n_rows=1, max_tabs_per_row=5, 24ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh expand_tabs=False, **kw): 25ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Constructor arguments: 26ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 27ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh select_command -- A callable which will be called when a tab is 28ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh selected. It is called with the name of the selected tab as an 29ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh argument. 30ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 31ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tabs -- A list of strings, the names of the tabs. Should be specified in 32ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh the desired tab order. The first tab will be the default and first 33ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh active tab. If tabs is None or empty, the TabSet will be initialized 34ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh empty. 35ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 36ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh n_rows -- Number of rows of tabs to be shown. If n_rows <= 0 or is 37ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh None, then the number of rows will be decided by TabSet. See 38ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh _arrange_tabs() for details. 39ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 40ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh max_tabs_per_row -- Used for deciding how many rows of tabs are needed, 41ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh when the number of rows is not constant. See _arrange_tabs() for 42ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh details. 43ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 44ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 45ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Frame.__init__(self, page_set, **kw) 46ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.select_command = select_command 47ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.n_rows = n_rows 48ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.max_tabs_per_row = max_tabs_per_row 49ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.expand_tabs = expand_tabs 50ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.page_set = page_set 51ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 52ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tabs = {} 53ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab2row = {} 54ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if tabs: 55ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab_names = list(tabs) 56ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 57ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab_names = [] 58ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._selected_tab = None 59ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab_rows = [] 60ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 61ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.padding_frame = Frame(self, height=2, 62ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh borderwidth=0, relief=FLAT, 63ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh background=self.cget('background')) 64ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.padding_frame.pack(side=TOP, fill=X, expand=False) 65ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 66ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._arrange_tabs() 67ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 68ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def add_tab(self, tab_name): 69ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Add a new tab with the name given in tab_name.""" 70ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not tab_name: 71ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise InvalidNameError("Invalid Tab name: '%s'" % tab_name) 72ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if tab_name in self._tab_names: 73ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise AlreadyExistsError("Tab named '%s' already exists" %tab_name) 74ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 75ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab_names.append(tab_name) 76ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._arrange_tabs() 77ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 78ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def remove_tab(self, tab_name): 79ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Remove the tab named <tab_name>""" 80ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not tab_name in self._tab_names: 81ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise KeyError("No such Tab: '%s" % page_name) 82ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 83ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab_names.remove(tab_name) 84ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._arrange_tabs() 85ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 86ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def set_selected_tab(self, tab_name): 87ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Show the tab named <tab_name> as the selected one""" 88ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if tab_name == self._selected_tab: 89ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return 90ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if tab_name is not None and tab_name not in self._tabs: 91ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise KeyError("No such Tab: '%s" % page_name) 92ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 93ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # deselect the current selected tab 94ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if self._selected_tab is not None: 95ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tabs[self._selected_tab].set_normal() 96ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._selected_tab = None 97ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 98ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if tab_name is not None: 99ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # activate the tab named tab_name 100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._selected_tab = tab_name 101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab = self._tabs[tab_name] 102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab.set_selected() 103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # move the tab row with the selected tab to the bottom 104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab_row = self._tab2row[tab] 105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab_row.pack_forget() 106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab_row.pack(side=TOP, fill=X, expand=0) 107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _add_tab_row(self, tab_names, expand_tabs): 109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not tab_names: 110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return 111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab_row = Frame(self) 113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab_row.pack(side=TOP, fill=X, expand=0) 114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab_rows.append(tab_row) 115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for tab_name in tab_names: 117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab = TabSet.TabButton(tab_name, self.select_command, 118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab_row, self) 119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if expand_tabs: 120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab.pack(side=LEFT, fill=X, expand=True) 121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab.pack(side=LEFT) 123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tabs[tab_name] = tab 124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab2row[tab] = tab_row 125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # tab is the last one created in the above loop 127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab.is_last_in_row = True 128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _reset_tab_rows(self): 130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh while self._tab_rows: 131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab_row = self._tab_rows.pop() 132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab_row.destroy() 133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab2row = {} 134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _arrange_tabs(self): 136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Arrange the tabs in rows, in the order in which they were added. 138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh If n_rows >= 1, this will be the number of rows used. Otherwise the 140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh number of rows will be calculated according to the number of tabs and 141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh max_tabs_per_row. In this case, the number of rows may change when 142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh adding/removing tabs. 143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # remove all tabs and rows 146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for tab_name in self._tabs.keys(): 147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tabs.pop(tab_name).destroy() 148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._reset_tab_rows() 149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not self._tab_names: 151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return 152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if self.n_rows is not None and self.n_rows > 0: 154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh n_rows = self.n_rows 155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # calculate the required number of rows 157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh n_rows = (len(self._tab_names) - 1) // self.max_tabs_per_row + 1 158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # not expanding the tabs with more than one row is very ugly 160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh expand_tabs = self.expand_tabs or n_rows > 1 161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh i = 0 # index in self._tab_names 162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for row_index in xrange(n_rows): 163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # calculate required number of tabs in this row 164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh n_tabs = (len(self._tab_names) - i - 1) // (n_rows - row_index) + 1 165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab_names = self._tab_names[i:i + n_tabs] 166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh i += n_tabs 167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._add_tab_row(tab_names, expand_tabs) 168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # re-select selected tab so it is properly displayed 170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh selected = self._selected_tab 171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.set_selected_tab(None) 172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if selected in self._tab_names: 173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.set_selected_tab(selected) 174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh class TabButton(Frame): 176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """A simple tab-like widget.""" 177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh bw = 2 # borderwidth 179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __init__(self, name, select_command, tab_row, tab_set): 181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Constructor arguments: 182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh name -- The tab's name, which will appear in its button. 184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh select_command -- The command to be called upon selection of the 186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tab. It is called with the tab's name as an argument. 187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Frame.__init__(self, tab_row, borderwidth=self.bw, relief=RAISED) 190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.name = name 192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.select_command = select_command 193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.tab_set = tab_set 194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.is_last_in_row = False 195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.button = Radiobutton( 197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self, text=name, command=self._select_event, 198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh padx=5, pady=1, takefocus=FALSE, indicatoron=FALSE, 199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh highlightthickness=0, selectcolor='', borderwidth=0) 200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.button.pack(side=LEFT, fill=X, expand=True) 201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._init_masks() 203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.set_normal() 204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _select_event(self, *args): 206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Event handler for tab selection. 207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh With TabbedPageSet, this calls TabbedPageSet.change_page, so that 209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh selecting a tab changes the page. 210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Note that this does -not- call set_selected -- it will be called by 212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh TabSet.set_selected_tab, which should be called when whatever the 213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tabs are related to changes. 214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.select_command(self.name) 217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return 218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def set_selected(self): 220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Assume selected look""" 221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._place_masks(selected=True) 222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def set_normal(self): 224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Assume normal look""" 225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._place_masks(selected=False) 226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _init_masks(self): 228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh page_set = self.tab_set.page_set 229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh background = page_set.pages_frame.cget('background') 230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # mask replaces the middle of the border with the background color 231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.mask = Frame(page_set, borderwidth=0, relief=FLAT, 232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh background=background) 233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # mskl replaces the bottom-left corner of the border with a normal 234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # left border 235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.mskl = Frame(page_set, borderwidth=0, relief=FLAT, 236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh background=background) 237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.mskl.ml = Frame(self.mskl, borderwidth=self.bw, 238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh relief=RAISED) 239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.mskl.ml.place(x=0, y=-self.bw, 240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh width=2*self.bw, height=self.bw*4) 241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # mskr replaces the bottom-right corner of the border with a normal 242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # right border 243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.mskr = Frame(page_set, borderwidth=0, relief=FLAT, 244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh background=background) 245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.mskr.mr = Frame(self.mskr, borderwidth=self.bw, 246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh relief=RAISED) 247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _place_masks(self, selected=False): 249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh height = self.bw 250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if selected: 251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh height += self.bw 252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.mask.place(in_=self, 254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh relx=0.0, x=0, 255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh rely=1.0, y=0, 256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh relwidth=1.0, width=0, 257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh relheight=0.0, height=height) 258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.mskl.place(in_=self, 260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh relx=0.0, x=-self.bw, 261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh rely=1.0, y=0, 262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh relwidth=0.0, width=self.bw, 263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh relheight=0.0, height=height) 264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh page_set = self.tab_set.page_set 266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if selected and ((not self.is_last_in_row) or 267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh (self.winfo_rootx() + self.winfo_width() < 268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh page_set.winfo_rootx() + page_set.winfo_width()) 269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh ): 270ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # for a selected tab, if its rightmost edge isn't on the 271ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # rightmost edge of the page set, the right mask should be one 272ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # borderwidth shorter (vertically) 273ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh height -= self.bw 274ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 275ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.mskr.place(in_=self, 276ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh relx=1.0, x=0, 277ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh rely=1.0, y=0, 278ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh relwidth=0.0, width=self.bw, 279ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh relheight=0.0, height=height) 280ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 281ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.mskr.mr.place(x=-self.bw, y=-self.bw, 282ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh width=2*self.bw, height=height + self.bw*2) 283ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 284ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # finally, lower the tab set so that all of the frames we just 285ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # placed hide it 286ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.tab_set.lower() 287ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 288ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TabbedPageSet(Frame): 289ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """A Tkinter tabbed-pane widget. 290ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 291ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Constains set of 'pages' (or 'panes') with tabs above for selecting which 292ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh page is displayed. Only one page will be displayed at a time. 293ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 294ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Pages may be accessed through the 'pages' attribute, which is a dictionary 295ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh of pages, using the name given as the key. A page is an instance of a 296ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh subclass of Tk's Frame widget. 297ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 298ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh The page widgets will be created (and destroyed when required) by the 299ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh TabbedPageSet. Do not call the page's pack/place/grid/destroy methods. 300ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 301ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Pages may be added or removed at any time using the add_page() and 302ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh remove_page() methods. 303ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 304ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 305ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh class Page(object): 306ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Abstract base class for TabbedPageSet's pages. 307ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 308ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Subclasses must override the _show() and _hide() methods. 309ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 310ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 311ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh uses_grid = False 312ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 313ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __init__(self, page_set): 314ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.frame = Frame(page_set, borderwidth=2, relief=RAISED) 315ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 316ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _show(self): 317ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise NotImplementedError 318ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 319ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _hide(self): 320ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise NotImplementedError 321ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 322ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh class PageRemove(Page): 323ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Page class using the grid placement manager's "remove" mechanism.""" 324ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh uses_grid = True 325ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 326ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _show(self): 327ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.frame.grid(row=0, column=0, sticky=NSEW) 328ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 329ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _hide(self): 330ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.frame.grid_remove() 331ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 332ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh class PageLift(Page): 333ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Page class using the grid placement manager's "lift" mechanism.""" 334ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh uses_grid = True 335ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 336ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __init__(self, page_set): 337ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh super(TabbedPageSet.PageLift, self).__init__(page_set) 338ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.frame.grid(row=0, column=0, sticky=NSEW) 339ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.frame.lower() 340ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 341ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _show(self): 342ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.frame.lift() 343ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 344ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _hide(self): 345ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.frame.lower() 346ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 347ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh class PagePackForget(Page): 348ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Page class using the pack placement manager's "forget" mechanism.""" 349ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _show(self): 350ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.frame.pack(fill=BOTH, expand=True) 351ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 352ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _hide(self): 353ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.frame.pack_forget() 354ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 355ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __init__(self, parent, page_names=None, page_class=PageLift, 356ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh n_rows=1, max_tabs_per_row=5, expand_tabs=False, 357ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh **kw): 358ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Constructor arguments: 359ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 360ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh page_names -- A list of strings, each will be the dictionary key to a 361ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh page's widget, and the name displayed on the page's tab. Should be 362ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh specified in the desired page order. The first page will be the default 363ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh and first active page. If page_names is None or empty, the 364ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh TabbedPageSet will be initialized empty. 365ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 366ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh n_rows, max_tabs_per_row -- Parameters for the TabSet which will 367ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh manage the tabs. See TabSet's docs for details. 368ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 369ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh page_class -- Pages can be shown/hidden using three mechanisms: 370ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 371ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh * PageLift - All pages will be rendered one on top of the other. When 372ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh a page is selected, it will be brought to the top, thus hiding all 373ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh other pages. Using this method, the TabbedPageSet will not be resized 374ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh when pages are switched. (It may still be resized when pages are 375ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh added/removed.) 376ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 377ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh * PageRemove - When a page is selected, the currently showing page is 378ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh hidden, and the new page shown in its place. Using this method, the 379ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh TabbedPageSet may resize when pages are changed. 380ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 381ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh * PagePackForget - This mechanism uses the pack placement manager. 382ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh When a page is shown it is packed, and when it is hidden it is 383ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh unpacked (i.e. pack_forget). This mechanism may also cause the 384ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh TabbedPageSet to resize when the page is changed. 385ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 386ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 387ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Frame.__init__(self, parent, **kw) 388ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 389ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.page_class = page_class 390ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.pages = {} 391ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._pages_order = [] 392ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._current_page = None 393ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._default_page = None 394ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 395ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.columnconfigure(0, weight=1) 396ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.rowconfigure(1, weight=1) 397ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 398ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.pages_frame = Frame(self) 399ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.pages_frame.grid(row=1, column=0, sticky=NSEW) 400ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if self.page_class.uses_grid: 401ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.pages_frame.columnconfigure(0, weight=1) 402ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.pages_frame.rowconfigure(0, weight=1) 403ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 404ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # the order of the following commands is important 405ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab_set = TabSet(self, self.change_page, n_rows=n_rows, 406ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh max_tabs_per_row=max_tabs_per_row, 407ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh expand_tabs=expand_tabs) 408ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if page_names: 409ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for name in page_names: 410ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.add_page(name) 411ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab_set.grid(row=0, column=0, sticky=NSEW) 412ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 413ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.change_page(self._default_page) 414ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 415ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def add_page(self, page_name): 416ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Add a new page with the name given in page_name.""" 417ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not page_name: 418ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise InvalidNameError("Invalid TabPage name: '%s'" % page_name) 419ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if page_name in self.pages: 420ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise AlreadyExistsError( 421ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh "TabPage named '%s' already exists" % page_name) 422ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 423ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.pages[page_name] = self.page_class(self.pages_frame) 424ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._pages_order.append(page_name) 425ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab_set.add_tab(page_name) 426ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 427ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if len(self.pages) == 1: # adding first page 428ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._default_page = page_name 429ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.change_page(page_name) 430ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 431ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def remove_page(self, page_name): 432ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Destroy the page whose name is given in page_name.""" 433ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not page_name in self.pages: 434ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise KeyError("No such TabPage: '%s" % page_name) 435ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 436ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._pages_order.remove(page_name) 437ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 438ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # handle removing last remaining, default, or currently shown page 439ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if len(self._pages_order) > 0: 440ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if page_name == self._default_page: 441ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # set a new default page 442ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._default_page = self._pages_order[0] 443ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 444ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._default_page = None 445ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 446ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if page_name == self._current_page: 447ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.change_page(self._default_page) 448ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 449ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab_set.remove_tab(page_name) 450ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh page = self.pages.pop(page_name) 451ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh page.frame.destroy() 452ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 453ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def change_page(self, page_name): 454ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Show the page whose name is given in page_name.""" 455ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if self._current_page == page_name: 456ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return 457ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if page_name is not None and page_name not in self.pages: 458ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise KeyError("No such TabPage: '%s'" % page_name) 459ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 460ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if self._current_page is not None: 461ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.pages[self._current_page]._hide() 462ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._current_page = None 463ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 464ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if page_name is not None: 465ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._current_page = page_name 466ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.pages[page_name]._show() 467ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 468ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._tab_set.set_selected_tab(page_name) 469ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 470ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehif __name__ == '__main__': 471ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # test dialog 472ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh root=Tk() 473ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tabPage=TabbedPageSet(root, page_names=['Foobar','Baz'], n_rows=0, 474ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh expand_tabs=False, 475ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh ) 476ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tabPage.pack(side=TOP, expand=TRUE, fill=BOTH) 477ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Label(tabPage.pages['Foobar'].frame, text='Foo', pady=20).pack() 478ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Label(tabPage.pages['Foobar'].frame, text='Bar', pady=20).pack() 479ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Label(tabPage.pages['Baz'].frame, text='Baz').pack() 480ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh entryPgName=Entry(root) 481ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh buttonAdd=Button(root, text='Add Page', 482ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh command=lambda:tabPage.add_page(entryPgName.get())) 483ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh buttonRemove=Button(root, text='Remove Page', 484ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh command=lambda:tabPage.remove_page(entryPgName.get())) 485ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh labelPgName=Label(root, text='name of page to add/remove:') 486ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh buttonAdd.pack(padx=5, pady=5) 487ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh buttonRemove.pack(padx=5, pady=5) 488ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh labelPgName.pack(padx=5) 489ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh entryPgName.pack(padx=5) 490ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh root.mainloop() 491