Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | """ |
2 | a couple of classes for implementing partial tabbed-page like behaviour | |
3 | """ | |
4 | ||
5 | from Tkinter import * | |
6 | ||
7 | class InvalidTabPage(Exception): pass | |
8 | class AlreadyExists(Exception): pass | |
9 | ||
10 | class PageTab(Frame): | |
11 | """ | |
12 | a 'page tab' like framed button | |
13 | """ | |
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')) | |
19 | self.button.pack() | |
20 | ||
21 | class TabPageSet(Frame): | |
22 | """ | |
23 | a set of 'pages' with TabButtons for controlling their display | |
24 | """ | |
25 | def __init__(self,parent,pageNames=[],**kw): | |
26 | """ | |
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. | |
31 | """ | |
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) | |
39 | self.defaultPage='' | |
40 | self.pages={} | |
41 | for name in pageNames: | |
42 | self.AddPage(name) | |
43 | ||
44 | def ChangePage(self,pageName=None): | |
45 | if pageName: | |
46 | if pageName in self.pages.keys(): | |
47 | self.activePage.set(pageName) | |
48 | else: | |
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) | |
54 | ## switch page | |
55 | self.pages[self.GetActivePage()]['page'].lift() | |
56 | ||
57 | def GetActivePage(self): | |
58 | return self.activePage.get() | |
59 | ||
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, | |
67 | value=pageName) | |
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) | |
73 | self.ChangePage() | |
74 | ||
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 | |
85 | self.defaultPage='' | |
86 | return | |
87 | if pageName==self.defaultPage: # set a new default page | |
88 | self.defaultPage=\ | |
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) | |
92 | self.ChangePage() | |
93 | ||
94 | if __name__ == '__main__': | |
95 | #test dialog | |
96 | root=Tk() | |
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) | |
112 | tabPage.ChangePage() | |
113 | root.mainloop() |