Notebook Widget for Tkinter. Easy to use, looks like that of the notebook used in the Tkinter based Python IDLE Options Window.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | #!usr/bin/env python
#tkNotebook
#Created By: Patrick T. Cossette <cold_soul79078@yahoo.com>
#tkNotebook allows users to make notebook widgets in Tk
#This software may be modified and redistributed, as long as any and all changes made
#From here on are stated, and ("Created By: Patrick T. Cossette <cold_soul79078@yahoo.com>") still remains somewhere
#In the code.
#This software is opensource, and free in hopes that it may be useful, and comes AS IS
#With no warrenty.
"""
Defines a Notebook class to be used with Tkinter. A Notebook instance
has the attributes change_tab, add_tab, destroy_tab, and focus_on.
change_tab: Internal Function, I don't suggest you call this directly.
add_tab: Creates a tab
destroy_tab: destroys the given tab
focus_on: Focuses on the given tab
The __init__ function creates three frames. One to hold the tabs together,
one to create the base to parent each tab's children, and one to hold the
base frame and the tab frame together.
Each tab is a Label with a default relief of "GROOVE". Each label uses
event bindings so that change_tab is called with the tab's ID Number as
an argument. Each tab relief, when selected is set by default to "RAISED"
For an exampe, view the source code, and run the module.
Created By: Patrick T. Cossette <cold_soul79078@yahoo.com>
"""
from Tkinter import *
class Notebook(Frame):
"""Notebook Widget"""
def __init__(self, parent, activerelief = RAISED, inactiverelief = RIDGE, xpad = 4, ypad = 6, activefg = 'black', inactivefg = 'black', **kw):
"""Construct a Notebook Widget
Notebook(self, parent, activerelief = RAISED, inactiverelief = RIDGE, xpad = 4, ypad = 6, activefg = 'black', inactivefg = 'black', **kw)
Valid resource names: background, bd, bg, borderwidth, class,
colormap, container, cursor, height, highlightbackground,
highlightcolor, highlightthickness, relief, takefocus, visual, width, activerelief,
inactiverelief, xpad, ypad.
xpad and ypad are values to be used as ipady and ipadx
with the Label widgets that make up the tabs. activefg and inactivefg define what
color the text on the tabs when they are selected, and when they are not
"""
#Make various argument available to the rest of the class
self.activefg = activefg
self.inactivefg = inactivefg
self.deletedTabs = []
self.xpad = xpad
self.ypad = ypad
self.activerelief = activerelief
self.inactiverelief = inactiverelief
self.kwargs = kw
self.tabVars = {} #This dictionary holds the label and frame instances of each tab
self.tabs = 0 #Keep track of the number of tabs
self.noteBookFrame = Frame(parent) #Create a frame to hold everything together
self.BFrame = Frame(self.noteBookFrame) #Create a frame to put the "tabs" in
self.noteBook = Frame(self.noteBookFrame, relief = RAISED, bd = 2, **kw) #Create the frame that will parent the frames for each tab
self.noteBook.grid_propagate(0) #self.noteBook has a bad habit of resizing itself, this line prevents that
Frame.__init__(self)
self.noteBookFrame.grid()
self.BFrame.grid(row =0, sticky = W)
self.noteBook.grid(row = 1, column = 0, columnspan = 27)
def change_tab(self, IDNum):
"""Internal Function"""
for i in (a for a in range(0, len(self.tabVars.keys()))):
if not i in self.deletedTabs: #Make sure tab hasen't been deleted
if i <> IDNum: #Check to see if the tab is the one that is currently selected
self.tabVars[i][1].grid_remove() #Remove the Frame corresponding to each tab that is not selected
self.tabVars[i][0]['relief'] = self.inactiverelief #Change the relief of all tabs that are not selected to "Groove"
self.tabVars[i][0]['fg'] = self.inactivefg #Set the fg of the tab, showing it is selected, default is black
else: #When on the tab that is currently selected...
self.tabVars[i][1].grid() #Re-grid the frame that corresponds to the tab
self.tabVars[IDNum][0]['relief'] = self.activerelief #Change the relief to "Raised" to show the tab is selected
self.tabVars[i][0]['fg'] = self.activefg #Set the fg of the tab, showing it is not selected, default is black
def add_tab(self, width = 2, **kw):
"""Creates a new tab, and returns it's corresponding frame
"""
temp = self.tabs #Temp is used so that the value of self.tabs will not throw off the argument sent by the label's event binding
self.tabVars[self.tabs] = [Label(self.BFrame, relief = RIDGE, **kw)] #Create the tab
self.tabVars[self.tabs][0].bind("<Button-1>", lambda Event:self.change_tab(temp)) #Makes the tab "clickable"
self.tabVars[self.tabs][0].pack(side = LEFT, ipady = self.ypad, ipadx = self.xpad) #Packs the tab as far to the left as possible
self.tabVars[self.tabs].append(Frame(self.noteBook, **self.kwargs)) #Create Frame, and append it to the dictionary of tabs
self.tabVars[self.tabs][1].grid(row = 0, column = 0) #Grid the frame ontop of any other already existing frames
self.change_tab(0) #Set focus to the first tab
self.tabs += 1 #Update the tab count
return self.tabVars[temp][1] #Return a frame to be used as a parent to other widgets
def destroy_tab(self, tab):
"""Delete a tab from the notebook, as well as it's corresponding frame
"""
self.iteratedTabs = 0 #Keep track of the number of loops made
for b in self.tabVars.values(): #Iterate through the dictionary of tabs
if b[1] == tab: #Find the NumID of the given tab
b[0].destroy() #Destroy the tab's frame, along with all child widgets
self.tabs -= 1 #Subtract one from the tab count
self.deletedTabs.append(self.iteratedTabs) #Apend the NumID of the given tab to the list of deleted tabs
break #Job is done, exit the loop
self.iteratedTabs += 1 #Add one to the loop count
def focus_on(self, tab):
"""Locate the IDNum of the given tab and use
change_tab to give it focus
"""
self.iteratedTabs = 0 #Keep track of the number of loops made
for b in self.tabVars.values(): #Iterate through the dictionary of tabs
if b[1] == tab: #Find the NumID of the given tab
self.change_tab(self.iteratedTabs) #send the tab's NumID to change_tab to set focus, mimicking that of each tab's event bindings
break #Job is done, exit the loop
self.iteratedTabs += 1 #Add one to the loop count
def demo():
def adjustCanvas(someVariable = None):
fontLabel["font"] = ("arial", var.get())
root = Tk()
root.title("tkNotebook Example")
note = Notebook(root, width= 400, height =400, activefg = 'red', inactivefg = 'blue') #Create a Note book Instance
note.grid()
tab1 = note.add_tab(text = "Tab One") #Create a tab with the text "Tab One"
tab2 = note.add_tab(text = "Tab Two") #Create a tab with the text "Tab Two"
tab3 = note.add_tab(text = "Tab Three") #Create a tab with the text "Tab Three"
tab4 = note.add_tab(text = "Tab Four") #Create a tab with the text "Tab Four"
tab5 = note.add_tab(text = "Tab Five") #Create a tab with the text "Tab Five"
Label(tab1, text = 'Tab one').grid(row = 0, column = 0) #Use each created tab as a parent, etc etc...
Label(tab1, text = "When something is changed on a tab,\ngoing to a different tab and back\nwill not reset, or effect it in any way.", font = ("Comic Sans MS", 12, "italic")).grid()
var = IntVar()
var.set(10)
scale = Scale(tab1, font = ("arial", 10), orient = 'horizontal', command = adjustCanvas, variable =var).grid()
fontLabel = Label(tab1, text = "TEXT", font = ("Arial", 10))
fontLabel.grid()
Label(tab2, text = 'Tab Two\n\n(Has focus first by using the focus_on attribute)\n\nThe tabs are colored red and blue via\nthe Notebook options. The default\nvalues are black on black :P', font = ("Comic Sans MS", 12, "italic")).grid()
Button(tab3, text = 'Destroy Tab Four!', command = lambda:note.destroy_tab(tab4)).grid()
Label(tab3, text = "Destroying a tab will remove it,\nand competely destoy all child widgets.\nOnce you destroy a tab, you have to recreate it\ncompletely in order to get it back.", font = ("Comic Sans MS", 12, "italic")).grid()
Label(tab4, text = 'Tab 4').grid()
Button(tab5, text = 'Tab One', command = lambda:note.focus_on(tab1)).grid(pady = 3)
Button(tab5, text = 'EXIT', width = 23, command = root.destroy).grid()
note.focus_on(tab2)
root.mainloop()
if __name__ == "__main__":
demo()
|
I read on a forum that somebody wanted to make a notebook in Tkinter from scratch, and the idea was quickly shot down, I remembered seeing a notebook widget in the Tkinter based Python IDLE on the options window and decided to make an easy-to-use notebook module, and this is what I came out with. Enjoy!