JHJL Here is a Snidget to create a collapsible label frame. It allows the user to click the frame's label to collapse/expand the frame (ie hide its contents and recover most of the space). The embedded child site frame can be floated into its own toplevel (you might want to use a key binding for this...)
package require snit
package require Tk
package require Ttk
snit::widget CollapsibleLabelFrame {
#
# We are basically wrapping a ttk::labelframe by attaching a
# label and embedding a child site frame.
#
# The label is used so that we can bind to it to determine
# when the user clicks it
#
# The embedded child site frame is a plain Tk frame (not ttk::frame)
# because (for my application) one cannot use wm manage on a
# ttk::frame
#
# Initial state 'open' or 'closed'
#
option -state \
-type {
snit::enum -values {open closed}
} -default open \
-configuremethod CFG-ChangeState \
-readonly 1
#
# Text to display
#
option -text -configuremethod CFG-LabelText -default ""
option -floattitle -default ""
component lframe
component label
component frame
delegate option -labelfont to label as -font
delegate option -labelfg to label as -foreground
#
# I'm using symbol characters within the font so that I don't
# have to worry colour. The downside is that the developer
# can choose a font that doesn't have these symbols...
#
# Because the attached label is a ttk::label, one could use a
# compound label + text and just manage the icon, but then
# what colour icon to use and what style for the current theme
#
variable open_symbol "\u25bc"
variable closed_symbol "\u25ba"
variable text ""
variable ginfo [list]
variable floatheight 100
variable floatwidth 300
constructor {args} {
install lframe using ttk::labelframe $win.lframe
install label using ttk::label $lframe.label \
-textvariable [myvar text] \
-font {arial 11 bold} \
-foreground blue
$lframe configure -labelwidget $label
install frame using frame $lframe.frame -borderwidth 0
bind $label <1> [mymethod toggle]
grid $frame -sticky news
grid columnconfigure $frame 0 -weight 1
grid rowconfigure $frame 0 -weight 1
grid $lframe -sticky news
grid columnconfigure $lframe 0 -weight 1
grid rowconfigure $lframe 0 -weight 1
grid columnconfigure $win 0 -weight 1
grid rowconfigure $win 0 -weight 1
$self configurelist $args
}
delegate method * to lframe
delegate option * to lframe
method CFG-LabelText {option value} {
set options($option) $value
$self UpdateLabel
}
method CFG-ChangeState {option value} {
$self toggle
set options($option) $value
}
method UpdateLabel {} {
set sym [expr {$options(-state) eq "open"
? $open_symbol
: $closed_symbol }]
set text "$sym $options(-text)"
}
method getframe {} {
# get the child site frame
return $frame
}
method open {} {
$self CFG-ChangeState -state open
}
method close {} {
$self CFG-ChangeState -state closed
}
method isfloating {} {
expr {$frame eq [winfo toplevel $frame]}
}
method toggle {} {
#
# Open or Close the frame
#
if {$options(-state) eq "open"} {
#
# grid remove remembers the slaves grid options :)
#
grid remove $frame
#
# Collapse the labelframe allowing a ltiile space for the
# label
#
set lh [winfo height $label]
$lframe configure -height [expr {$lh + 2}]
set options(-state) closed
} else {
#
# Don't bother if the frame has been floated into a toplevel
#
if {![$self isfloating]} {
grid $frame
set options(-state) open
}
}
$self UpdateLabel
}
method float {} {
#
# Float the embedded frame as a toplevel
# or reparent back into its container
#
#
# Check if frame is masquerading as a Toplevel
# (wm manage'd frames keep their names
#
if { ![$self isfloating] } {
#
# Not currently a toplevel, remem
#
# I'm not sure whether wm manage does a 'remove' or a 'forget'
# so I note the current grid options for the frame
#
set ginfo [grid info $frame]
#
# Remove from paned window and then get Window Manager
# to manage the frame
#
wm manage $frame
wm title $frame $options(-floattitle)
#
# Make it the same size as the labelframe
#
set height [winfo height $lframe]
set width [winfo width $lframe]
wm geometry $frame ${width}x${height}
#
# Capture close event on new Toplevel and reparent
#
wm protocol $frame WM_DELETE_WINDOW [mymethod float]
#
# Collapse the labelframe to recover the space vertical
#
$self close
} else {
#
# Reparent
#
wm forget $frame
#
# Open the containing labelframe
# and manage using the saved settings
#
$self open
grid $frame {*}$ginfo
}
}
}
if {0} {
catch {destroy .clf}
set clf [CollapsibleLabelFrame .clf \
-text "Click Me" \
-labelfg blue \
-floattitle "Whoo Hoo" \
]
pack $clf -fill both -expand 0
set f [$clf getframe]
set b [ttk::button $f.b -text "Float Me" -command [list $clf float]]
pack $b
}