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 ---- 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]): style theme settings default { style layout Plain.TNotebook.Tab null } ttk::notebook $nb -style Plain.TNotebook ---- [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. ---- [Flame] A [notebook] can change its tab position like this: ttk::style configure ENNotebook.TNotebook -tabposition en ttk::notebook .nb -style ENNotebook.TNotebook ---- [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" } ---- [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.) ====== 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) $what } 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 what [$win identify tab $x $y] 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 { $x < $winstate(x,$win) } { $win insert 0 $winstate(t,$win) set winstate(t,$win) 0 } else { $win insert end $winstate(t,$win) set winstate(t,$win) [expr {[$win index end]-1}] } } else { $win insert $what $winstate(t,$win) set winstate(t,$win) $what } } pack [ttk::notebook .test] foreach x {1 2 3 4 5} y {Foo Bar Baz Boing Sprocket} { .test add [frame .f$x -height 200 -width 200] -text $y } ====== ---- !!!!!! %|[Category Widget]|% !!!!!!