2 a couple of classes for implementing partial tabbed-page like behaviour
7 class InvalidTabPage(Exception): pass
8 class AlreadyExists(Exception): pass
12 a 'page tab' like framed button
14 def __init__(self
,parent
):
15 Frame
.__init
__(self
, parent
,borderwidth
=2,relief
=RIDGE
)
16 self
.button
=Radiobutton(self
,padx
=5,pady
=5,takefocus
=FALSE
,
17 indicatoron
=FALSE
,highlightthickness
=0,
18 borderwidth
=0,selectcolor
=self
.cget('bg'))
21 class TabPageSet(Frame
):
23 a set of 'pages' with TabButtons for controlling their display
25 def __init__(self
,parent
,pageNames
=[],**kw
):
27 pageNames - a list of strings, each string will be the dictionary key
28 to a page's data, and the name displayed on the page's tab. Should be
29 specified in desired page order. The first page will be the default
30 and first active page.
32 Frame
.__init
__(self
, parent
, kw
)
33 self
.grid_location(0,0)
34 self
.columnconfigure(0,weight
=1)
35 self
.rowconfigure(1,weight
=1)
36 self
.tabBar
=Frame(self
)
37 self
.tabBar
.grid(row
=0,column
=0,sticky
=EW
)
38 self
.activePage
=StringVar(self
)
41 for name
in pageNames
:
44 def ChangePage(self
,pageName
=None):
46 if pageName
in self
.pages
.keys():
47 self
.activePage
.set(pageName
)
49 raise InvalidTabPage
, 'Invalid TabPage Name'
50 ## pop up the active 'tab' only
51 for page
in self
.pages
.keys():
52 self
.pages
[page
]['tab'].config(relief
=RIDGE
)
53 self
.pages
[self
.GetActivePage()]['tab'].config(relief
=RAISED
)
55 self
.pages
[self
.GetActivePage()]['page'].lift()
57 def GetActivePage(self
):
58 return self
.activePage
.get()
60 def AddPage(self
,pageName
):
61 if pageName
in self
.pages
.keys():
62 raise AlreadyExists
, 'TabPage Name Already Exists'
63 self
.pages
[pageName
]={'tab':PageTab(self
.tabBar
),
64 'page':Frame(self
,borderwidth
=2,relief
=RAISED
)}
65 self
.pages
[pageName
]['tab'].button
.config(text
=pageName
,
66 command
=self
.ChangePage
,variable
=self
.activePage
,
68 self
.pages
[pageName
]['tab'].pack(side
=LEFT
)
69 self
.pages
[pageName
]['page'].grid(row
=1,column
=0,sticky
=NSEW
)
70 if len(self
.pages
)==1: # adding first page
71 self
.defaultPage
=pageName
72 self
.activePage
.set(self
.defaultPage
)
75 def RemovePage(self
,pageName
):
76 if not pageName
in self
.pages
.keys():
77 raise InvalidTabPage
, 'Invalid TabPage Name'
78 self
.pages
[pageName
]['tab'].pack_forget()
79 self
.pages
[pageName
]['page'].grid_forget()
80 self
.pages
[pageName
]['tab'].destroy()
81 self
.pages
[pageName
]['page'].destroy()
82 del(self
.pages
[pageName
])
83 # handle removing last remaining, or default, or active page
84 if not self
.pages
: # removed last remaining page
87 if pageName
==self
.defaultPage
: # set a new default page
89 self
.tabBar
.winfo_children()[0].button
.cget('text')
90 if pageName
==self
.GetActivePage(): # set a new active page
91 self
.activePage
.set(self
.defaultPage
)
94 if __name__
== '__main__':
97 tabPage
=TabPageSet(root
,pageNames
=['Foobar','Baz'])
98 tabPage
.pack(expand
=TRUE
,fill
=BOTH
)
99 Label(tabPage
.pages
['Foobar']['page'],text
='Foo',pady
=20).pack()
100 Label(tabPage
.pages
['Foobar']['page'],text
='Bar',pady
=20).pack()
101 Label(tabPage
.pages
['Baz']['page'],text
='Baz').pack()
102 entryPgName
=Entry(root
)
103 buttonAdd
=Button(root
,text
='Add Page',
104 command
=lambda:tabPage
.AddPage(entryPgName
.get()))
105 buttonRemove
=Button(root
,text
='Remove Page',
106 command
=lambda:tabPage
.RemovePage(entryPgName
.get()))
107 labelPgName
=Label(root
,text
='name of page to add/remove:')
108 buttonAdd
.pack(padx
=5,pady
=5)
109 buttonRemove
.pack(padx
=5,pady
=5)
110 labelPgName
.pack(padx
=5)
111 entryPgName
.pack(padx
=5)