Search code examples
user-interfacetclprototypetk-toolkit

Integrate Tk grid widget into notebook layout


I want to quickly prototype a GUI and thought that Tk could be simple to learn. However, I failed to integrate a sample grid view (frame) into one of the tabs of the notebook widget. The pack command places the grid on top of the notebook and I could not figure out the correct option. Or is my approach anyhow wrong?

Here is the code:

ttk::frame .c
ttk::frame .c.f -borderwidth 5 -relief sunken -width 200 -height 100
ttk::label .c.namelbl -text Name
ttk::entry .c.name
ttk::checkbutton .c.one -text One -variable one -onvalue 1; set one 1
ttk::checkbutton .c.two -text Two -variable two -onvalue 1; set two 0
ttk::checkbutton .c.three -text Three -variable three -onvalue 1; set three 1
ttk::button .c.ok -text Okay
ttk::button .c.cancel -text Cancel

grid .c -column 0 -row 0
grid .c.f -column 0 -row 0 -columnspan 3 -rowspan 2
grid .c.namelbl -column 3 -row 0 -columnspan 2
grid .c.name -column 3 -row 1 -columnspan 2
grid .c.one -column 0 -row 3
grid .c.two -column 1 -row 3
grid .c.three -column 2 -row 3
grid .c.ok -column 3 -row 3
grid .c.cancel -column 4 -row 3

# Notebook --> shall contain above grid in third tab
ttk::notebook .n  -width 600 -height 200
ttk::frame .n.f1; 
ttk::frame .n.f2; 
.n add .n.f1 -text "FirstTab"
.n add .n.f2 -text "SecondTab"
.n add .c -text "GridContent"
pack [label .n.f1.f1 -background red -foreground white -text "First"]
pack [label .n.f2.f2 -background red -foreground white -text "Second"]
pack .c 
pack .n 
ttk::notebook::enableTraversal .n

Solution

  • The content widgets of a ttk::notebook must be higher in the stacking order than the notebook for it to work correctly, and must be managed by the notebook itself and not by pack or grid (though their contents can be managed any way you want); notebooks are a special kind of geometry manager as well as being a widget. (Tk has several other widgets that do this too.)

    To fix the stacking order, either create the .c widget after the .n widget, or raise .c after creating .n. Note that a parent widget's children (except for toplevels, and menus in a few circumstances) always come on top of the parent, and are always bounded/clipped by their parent.

    To fix the management issue, simply don't pack .c; adding it to the notebook is enough. You may pack or grid the contents of .c as you see fit.


    With those two small fixes, your UI appears to work.

    ttk::frame .c
    ttk::frame .c.f -borderwidth 5 -relief sunken -width 200 -height 100
    ttk::label .c.namelbl -text Name
    ttk::entry .c.name
    ttk::checkbutton .c.one -text One -variable one -onvalue 1; set one 1
    ttk::checkbutton .c.two -text Two -variable two -onvalue 1; set two 0
    ttk::checkbutton .c.three -text Three -variable three -onvalue 1; set three 1
    ttk::button .c.ok -text Okay
    ttk::button .c.cancel -text Cancel
    
    grid .c -column 0 -row 0
    grid .c.f -column 0 -row 0 -columnspan 3 -rowspan 2
    grid .c.namelbl -column 3 -row 0 -columnspan 2
    grid .c.name -column 3 -row 1 -columnspan 2
    grid .c.one -column 0 -row 3
    grid .c.two -column 1 -row 3
    grid .c.three -column 2 -row 3
    grid .c.ok -column 3 -row 3
    grid .c.cancel -column 4 -row 3
    
    # Notebook --> shall contain above grid in third tab
    ttk::notebook .n  -width 600 -height 200
    ttk::frame .n.f1; 
    ttk::frame .n.f2; 
    .n add .n.f1 -text "FirstTab"
    .n add .n.f2 -text "SecondTab"
    .n add .c -text "GridContent"
    raise .c;   # <<<< YES! YOU DO WANT THIS! <<<< YES! <<<< YES! <<<< YES! <<<<
    pack [label .n.f1.f1 -background red -foreground white -text "First"]
    pack [label .n.f2.f2 -background red -foreground white -text "Second"]
    # pack .c;  # <<<< NO! YOU DO NOT WANT THIS! <<<< NO! <<<< NO! <<<< NO! <<<<
    pack .n 
    ttk::notebook::enableTraversal .n