Monday, June 24, 2013

ttk Notebook demo for Py2

There is a very nice ttk Notebook demo on a very cleverly named blog called Py in my eye. Note: there are very few differences between the Python 3 version of this demo and the Python 2 version, other than
For a Python 2 version of Jane's demo, see this Gist. To help myself understand what was going on, I forced myself to decompose that stellar example into this super easy demo:
#! /usr/bin/env python

from Tkinter import *
from ttk import *

root = Tk() # create a top-level window

master = Frame(root, name='master') # create Frame in "root"
master.pack(fill=BOTH) # fill both sides of the parent

root.title('EZ') # title for top-level window
# quit if the window is deleted
root.protocol("WM_DELETE_WINDOW", master.quit)

nb = Notebook(master, name='nb') # create Notebook in "master"
nb.pack(fill=BOTH, padx=2, pady=3) # fill "master" but pad sides

# create each Notebook tab in a Frame
master_foo = Frame(nb, name='master-foo')
Label(master_foo, text="this is foo").pack(side=LEFT)
# Button to quit app on right
btn = Button(master_foo, text="foo", command=master.quit)
nb.add(master_foo, text="foo") # add tab to Notebook

# repeat for each tab
master_bar = Frame(master, name='master-bar')
Label(master_bar, text="this is bar").pack(side=LEFT)
btn = Button(master_bar, text="bar", command=master.quit)
nb.add(master_bar, text="bar")

# start the app
if __name__ == "__main__":
    master.mainloop() # call master's Frame.mainloop() method.
    #root.destroy() # if mainloop quits, destroy window
Some notes:
  • The original demo puts the notebook in a frame, in another frame inside the top-level window, but you can just go nb->frame->root, and skip the extra frame. Not sure what you gain or lose.
  • If you want to see the demo decomposed, I converted the original demo as a script in the Gist.
  • You don't have to call Tk() to create a top-level window, Frame will do it for you. Then you can access the window via the master attribute of Frame.
  • If you call the Frame's quit() method, it will destroy the window for you, so the last line, root.destroy(), is not necessary.
  • If you don't bind the "WM_DELETE_WINDOW" protocol to Frame's quit() method, you will get a traceback when root.destroy() is called, saying that it can't destroy the window because it's already been deleted.
  • Use fill=BOTH if your labels and buttons are smaller than the parents they occupy if you want them to extend to both sides.
  • All of these demos are included in your Python distribution. On MS Windows it is here: C:\Python27\tcl\tk8.5\demos
Fork me on GitHub