A [Tk] (or rather [Ttk]) [widget] that stacks a bunch of widgets on top of each other in a window, with some tabs at the top to allow users to select between the widgets. A common idiom in Windows's Properties dialogs. : http://www.tcl.tk/man/tcl8.5/TkCmd/ttk_notebook.htm ---- **Tips and Tricks** <> Use [notebook] as a '''pages manager''' A [notebook] may be used as a '''pages manager'''[http://wiki.tcl.tk/17852] by using a style to turn off the tabs, like this (by [Joe English]): ====== ttk::style theme settings default { ttk::style layout Plain.TNotebook.Tab null } ttk::notebook $nb -style Plain.TNotebook ====== Alternatively, you can set it on the current style (useful on some platforms) with: ====== ttk::style layout Plain.TNotebook.Tab null ttk::notebook $nb -style Plain.TNotebook ====== <> ---- <> Current selected tab info [tonytraductor] I have a question. Using a ttk::notebook, how do I pass the currently selected tab's info to a process? Answer: [[$nb select]] returns the widget name of the currently selected pane. In addition, the string "current" may be used as a tab identifier. ---- <> <> Change tab position [Flame] A [notebook] can change its tab position like this: ttk::style configure ENNotebook.TNotebook -tabposition en ttk::notebook .nb -style ENNotebook.TNotebook ---- <> <> Tab list scrolling code [Flame] Here is some code to add tab list scrolling to a [notebook]. The code is not optimized, supports only ne-oriented tabs, and assumes user does not change tab states. ====== namespace eval SNotebook { # create scroll buttons foreach anchor {n s e w} arrow {uparrow downarrow leftarrow rightarrow} { set uanchor [string toupper $anchor] ttk::style layout ${uanchor}Button.TButton [list Button.focus -sticky nswe -children [list ${uanchor}Button.$arrow -sticky nswe]] } variable scrollpos variable hsizes variable tabheight proc _updatehsizes {nb} { if {![winfo exists $nb.escroll]} { ttk::button $nb.escroll -style EButton.TButton -command [string map [list \$nb $nb] { if {$::SNotebook::scrollpos($nb)>0} { incr ::SNotebook::scrollpos($nb) -1 ::SNotebook::_scroll_notebook $nb } }] } if {![winfo exists $nb.wscroll]} { ttk::button $nb.wscroll -style WButton.TButton -command [string map [list \$nb $nb] { if {$::SNotebook::scrollpos($nb)+1<[llength [$nb tabs]]} { incr ::SNotebook::scrollpos($nb) ::SNotebook::_scroll_notebook $nb } }] } variable hsizes variable tabheight set ntabs [$nb index end] set tabs [$nb tabs] ttk::notebook .tmp -style [$nb cget -style] set p0 [winfo reqwidth .tmp] set hsizes($nb) $p0 for {set i 0} {$i<$ntabs} {incr i} { set tab [lindex $tabs $i] if {1} { ;# theme-independent, but could have side effects eval .tmp add [ttk::frame .tmp.f$i] [::SNotebook::$nb tab $tab] -state normal update idletasks set hsizes($tab) [expr [winfo reqwidth .tmp]-$p0] set p0 [winfo reqwidth .tmp] } else { ;# there is a theme-dependable constant, which includes padding and tab margins eval ttk::label .tmp2 -style TNotebook.Tab [dict remove [::SNotebook::$nb tab $tab] -sticky] set hsizes($tab) [expr [winfo reqwidth .tmp2]+10] destroy .tmp2 } } destroy .tmp ttk::label .tmp -style TNotebook.Tab set tabheight [winfo reqheight .tmp] destroy .tmp } proc _scroll_notebook {nb} { ;# assumes tabposition is nw or ne variable scrollpos variable hsizes variable tabheight if {![info exists scrollpos($nb)]} { set scrollpos($nb) 0 } set startindex $scrollpos($nb) for {set i 0} {$i<$startindex} {incr i} { ::SNotebook::$nb hide $i } set ntabs [$nb index end] set tabs [$nb tabs] set availw [winfo width $nb] set reqw $hsizes($nb) set overflow 0 for {} {$i<$ntabs} {incr i} { set tab [lindex $tabs $i] incr reqw $hsizes($tab) ::SNotebook::$nb add $tab if {$reqw>$availw} { incr i set overflow 1 break } } for {set j $i} {$j<$ntabs} {incr j} { ::SNotebook::$nb hide [lindex $tabs $j] } set h $tabheight set eh [expr 4*$h/5] if {$startindex>0} { set ew [expr $eh*[winfo reqwidth $nb.escroll]/[winfo reqheight $nb.escroll]] place $nb.escroll -x 0 -y 0 -width $ew -height $eh } else { place forget $nb.escroll } if {$overflow} { set ew [expr $eh*[winfo reqwidth $nb.wscroll]/[winfo reqheight $nb.wscroll]] place $nb.wscroll -relx 1.0 -x -$ew -y 0 -width $ew -height $eh } else { place forget $nb.wscroll } } proc snotebook {path args} { ttk::notebook $path {*}$args _updatehsizes $path bindtags $path [linsert [bindtags $path] 1 SNotebook] bind SNotebook {::SNotebook::_scroll_notebook %W} rename ::$path ::SNotebook::$path proc ::$path {cmd args} [string map [list \$path $path] { switch $cmd { index - configure - cget - identify - instate - select - state - tabs { ::SNotebook::$path $cmd {*}$args } default { bind SNotebook {} set res [::SNotebook::$path $cmd {*}$args] ::SNotebook::_updatehsizes $path bind SNotebook {::SNotebook::_scroll_notebook %W} ::SNotebook::_scroll_notebook $path return $res } } }] return $path } } ::SNotebook::snotebook .nb pack .nb -fill both -expand true set i 0 foreach theme [ttk::themes] { frame .f$i pack [button .f$i.b -text "Theme: $theme" -command "ttk::setTheme $theme"] -anchor nw .nb add .f$i -text "Tab $i" incr i } for {} {$i<20} {incr i} { .nb add [text .t$i] -text "Tab $i" } ====== ---- <> <> dragging tab code [MG] just started playing with the ttk::notebook (Aug 2011), and wrote a little package to allow dragging the tabs with the right mousebutton to reorder them. Only tested on Windows, and only with one theme, but it seems to work OK (though there's a little jumping when you move a switch a small tab with a larger one, which I haven't fixed yet). Requires a version of ttk::notebook that supports ''$notebook identify tab $x $y'' - 8.5.7 doesn't, but 8.6.1 does. (It's in the docs online for 8.5, though, so was presumably added into 8.5.8 or 8.5.9.) (Using the left mousebutton might be better, but that means making it play nice with the notebook's existing bindings, and it's long since time I went to bed, so that's a task for another day, too.) [MG] I just found this again (July 2012), and thought I'd spruce it up a bit. It no longer stutters, and it now uses the left mouse button for dragging instead of the right, which is both more user-friendly and looks better, because the tab always comes to the front before you start dragging it. ====== namespace eval tabdrag {} bind TNotebook {+tabdrag::destroy %W} bind TNotebook {+tabdrag::click %W %x %y} bind TNotebook {+tabdrag::release %W %x %y} bind TNotebook {+tabdrag::move %W %x %y} proc ::tabdrag::destroy {win} { variable winstate; array unset winstate ?,$win } proc ::tabdrag::click {win x y} { variable winstate; set what [$win identify tab $x $y] if { $what eq "" || [$win index end] <= 1} { return; } set winstate(x,$win) $x set winstate(t,$win) [lindex [$win tabs] $what] set winstate(e,$win) 0 } proc ::tabdrag::release {win x y} { variable winstate; array unset winstate ?,$win } proc ::tabdrag::move {win x y} { variable winstate; if { ![info exists winstate(x,$win)] || ![info exists winstate(t,$win)] || $winstate(t,$win) eq "" } { return; } set where [$win identify tab $x $y] if { [info exists winstate(a,$win)] } { if { $x < $winstate(a,$win) && $where < $winstate(i,$win) } { unset -nocomplain winstate(a,$win) winstate(i,$win) winstate(j,$win) } elseif { $x > $winstate(a,$win) && $where > $winstate(i,$win) } { unset -nocomplain winstate(a,$win) winstate(i,$win) winstate(j,$win) } } if { $where ne "" } { set what [lindex [$win tabs] $where] } else { set what "" } if { $what eq $winstate(t,$win) } { return; } if { $what eq "" } { # Not over a tab - check to see if we're before or after where we started if { $winstate(e,$win) } { return; } set winstate(e,$win) 1 if { $x < $winstate(x,$win) } { $win insert 0 $winstate(t,$win) } else { $win insert end $winstate(t,$win) } #unset -nocomplain winstate(j,$win) winstate(a,$win) winstate(i,$win) set winstate(x,$win) $x } else { set winstate(e,$win) 0 if { [info exists winstate(j,$win)] && $what eq $winstate(j,$win) } { if { (($x > $winstate(x,$win) && $x > $winstate(a,$win)) || ($x < $winstate(x,$win) && $x < $winstate(a,$win))) } { return;# avoid stuttering when jumping a bigger tab } } $win insert $what $winstate(t,$win) set winstate(j,$win) $what set winstate(a,$win) $x set winstate(i,$win) $where } } pack [ttk::notebook .test] foreach x {Foo Bar Baz Boing Sprocket} { .test add [frame .f$x -height 200 -width 200] -text $x } ====== ---- <> Tab background color [http://groups.google.com/group/comp.lang.tcl/browse_thread/thread/fba4859ab6c7ca9b#%|%Don on clt%|%]: I am trying to specify the background tab colors in a TNotebook, in particular the background color of the tab for the selected page ====== toplevel .top wm geometry .top 500x400+40+50; update .top configure -background wheat ttk::style configure TNotebook -background wheat ttk::style configure TNotebook.Tab -background plum ttk::style map TNotebook.Tab -background [list disabled plum selected green] ttk::notebook .top.nb -width 300 -height 200 .top.nb add [frame .top.nb.f1 -bg wheat] -text "First tab" .top.nb add [frame .top.nb.f2 -bg wheat] -text "Second tab" .top.nb add [frame .top.nb.f3 -bg wheat] -text "Third tab" place .top.nb -in .top -x 100 -y 100 ====== ---- <> <> Widget