Hi!
Thanks to Ken I have implemented a frame in which I can add/delete buttons. The problem is that I need to have a scrollable frame otherwise the frame will keep growing and I won't be able to select the buttons at the bottom. This was solved by inserting the button frame inside a canvas. My problem now is that the scrollbar does not work, the frame keeps growing anyway. I have tried inserting
$cv configure -scrollregion [$cv bbox all] (see code below) in InsertFrame proc but this does not make any difference.
Please help!!!
#!/usr/local/bin/wish
#exec wish "$0" "$@"
#-----------------------------------------------------------------------------
##############################
frame .top -borderwidth 2
pack .top -fill x
#
#
#MENUS
#
menu .top.menuBar -tearoff 0
set f .top.menuBar.file
set fc .top.menuBar.func
set h .top.menuBar.help
set edit .top.menuBar.edit
#File menu
.top.menuBar add cascade -menu $f -label "File" -font {Helvetica 14 bold} -underline 0
menu $f -tearoff 1
$f add command -label "New" -font {Helvetica 12 bold} -underline 0 -command {}
$f add command -label "Open" -font {Helvetica 12 bold} -underline 0 -command {}
$f add command -label "Save" -font {Helvetica 12 bold} -underline 0 -command {}
$f add separator
$f add command -label "Exit" -font {Helvetica 12 bold} -underline 1 -command {exit} -accelerator "Meta-q"
#Edit
.top.menuBar add cascade -menu $edit -label "Edit" -font {Helvetica 14 bold} -underline 0
menu $edit -tearoff 1
$edit add command -label "Add before" -font {Helvetica 12 bold} -underline 0 -command {}
$edit add command -label "Add after" -font {Helvetica 12 bold} -underline 0 -command {}
$edit add command -label "Delete" -font {Helvetica 12 bold} -underline 0 -command {}
#Functions
.top.menuBar add cascade -menu $fc -label "Functions" -font {Helvetica 14 bold} -underline 0
menu $fc -tearoff 1
$fc add command -label "Import" -font {Helvetica 12 bold} -underline 0 -command {}
#help menu
.top.menuBar add cascade -menu $h -label "Help" -font {Helvetica 14 bold} -underline 0
menu $h -tearoff 1
$h add command -label "About.." -font {Helvetica 12 bold} -command {About} -underline 0
global f h fc edit
# bind accelerator keys
bind . <Meta-q> {exit}
# for frame select
bind . <ButtonPress-1> {
FrameSelect %W
}
. configure -menu .top.menuBar
# main window
#
wm title . "ZMAP MACRO BUILDER"
wm geometry . 400x300
wm minsize . 400 300
####
##
###
#function frame
set incfr 0
# Initialize a counter to help us create
# unique frame names on demand.
set frameCounter [incr incfr]
global incfr frameCounter
#
# Lower frame holds text output
#
#frame .logfr
#set log [text .logfr.log -width 50 -height 5 # -borderwidth 3 -relief sunken -setgrid true # -yscrollcommand {.logfr.scroll set} -font {courier 9}]
#scrollbar .logfr.scroll -command {.logfr.log yview}
#pack .logfr.scroll -side right -fill y
#pack .logfr.log -side left -fill both -expand true
#pack .logfr -side top -fill both -expand true
###########
# FUNCTIONS
############
###
# MAKE PROCESS FRAME
###
proc MakeFrame {w} {
global first
global cv
# make frame
puts "frame: $w"
frame $w -borderwidth 4
set item [$cv create window 1c 1c -window $w -anchor nw]
pack $w -side top -fill x
#checkbutton
checkbutton $w.cb -text "Empty " -variable dummy -command {} -padx 10
#button
button $w.b -text "Parameters..." -width 10 -command {} -padx 20
pack $w.cb $w.b -padx 5 -side left
update
if {$first } {
puts "in first"
set first 0
$cv configure -width [expr [winfo reqwidth $w.b] +10]
$cv configure -height [expr [winfo reqheight $w.b] * 5]
$cv configure -yscrollincrement [winfo reqheight $w.b]
set toto [expr [winfo reqwidth $w.b] +10]
puts $toto
set toto [expr [winfo reqheight $w.b] * 5]
puts $toto
}
$cv configure -scrollregion [$cv bbox all]
# $cv configure -scrollregion [$cv bbox $item]
# $cv yview 0
}
###############
proc mkScrollCanvas {w f width height } {
set c [canvas $w.c -width $width -height $height -bd 4 -relief ridge -yscrollcommand "$w.yscroll set"]
set s [scrollbar $w.yscroll -relief sunken -command "$w.c yview"]
set l [label $w.l -text "xxx"]
pack $l -side top -fill x -in $f
pack $s -side right -fill y -padx 1 -in $f
pack $c -side top -fill both -expand 1 -in $f
return $c
}
##################################
# FrameSelect
#
# Called by a binding to select a frame.
##################################
proc FrameSelect {w} {
global selected
puts "in FrameSelect"
# If the user clicked on a child widget
# rather than its parent frame, cycle up
# to the parent frame. Note that this
# simple algorithm *doesn't* allow for
# another frame to be nested in our
# containing frame. It also relies on you
# not changing the frame's class to
# anything other than "Frame" to work
# properly.
while {([winfo class $w] != "Frame"
&& ("$w" != "."} {
set w [winfo parent $w]
}
# "De-select" whatever is currently
# selected. This also handles "toggling"
# an already selected frame by clicking on
# it again.
if {[info exists selected(current)]} {
$selected(current) configure -relief $selected(relief)
}
#if {[info exists selected(current)]
#&& ($selected(current) == $w)} {
# The user clicked on the frame already
# selected. Simply "de-select" the frame
# and return.
#unset selected(current)
#return
#} else {
# Highlight the selected frame by
# changing its border to groove. To be
# visible, the frame must have its
# border width (-bd) set to a value
# greater than 2.
set selected(relief) [$w cget -relief]
set selected(current) $w
$w configure -relief groove
#}
}
# Create a symbolic bindtag called
# "selectable", that invokes our FrameSelect
# procedure in response to a left-click.
bind selectable <ButtonPress-1> {
FrameSelect %W
}
##################################
# InsertFrame
#
# Create a frame on demand. If another frame
# is selected, the new frame is packed
# before the selected frame; otherwise, the
# new frame is packed after all existing
# frames.
##################################
proc InsertFrame {} {
global selected
global frameCounter
global cv
set i [incr frameCounter]
#display first frame (default)
set f $cv.fr$i
puts $f
MakeFrame $f
if {[info exists selected(current)]} {
# If a frame is selected, insert the new
# frame in front of the selected one in
# the packing order.
pack $f -before $selected(current) -padx 2 -pady 2 -anchor w
} else {
# If no frame is selected, pack the new
# frame after all other frames.
pack $f -padx 2 -pady 2 -anchor w
}
$cv configure -scrollregion [$cv bbox all]
# Insert our "selectable" bindtag at the
# beginning of the bindtag path for the
# frame.
bindtags $f [linsert [bindtags $f] 0 selectable]
# Uncomment the following lines if you
# want the frame toggling binding active
# for the contents of the frame as well.
# bindtags $f.cb [linsert [bindtags $f.cb] 0 selectable]
# bindtags $f.b [linsert [bindtags $f.b] 0 selectable]
pack $f.cb -padx 2 -pady 2 -anchor w
pack $f.b -padx 2 -pady 2
}
##################################
# DeleteFrame
#
# Delete the currently selected frame. If no
# frame is selected, nothing happens.
##################################
proc DeleteFrame {} {
global selected
if {[info exists selected(current)]} {
destroy $selected(current)
unset selected(current)
}
}
# Define virtual events, which allows us to
# use mutiple bindings to perform the same
# task.
event add <<Insert>> <Control-KeyPress-a> <KeyPress-Insert>
event add <<Delete>> <Control-KeyPress-d> <KeyPress-Delete>
# Bind to the toplevel window, so that these
# bindings are active no matter which widget
# has focus.
bind . <<Insert>> InsertFrame
bind . <<Delete>> DeleteFrame
###### MAIN #########
#set first frame (default)
frame .f -height 1
pack .f
set first 1
set cv [mkScrollCanvas .f .f 0 0]
#display first frame (default)
MakeFrame $cv.fr1
#frames
# for buttons
frame .btfr -borderwidth 10
pack .btfr -fill x
#
# Action Buttons
#
set but [button .btfr.run -background #88ff88 -activebackground #88ff88 -text "Run" -command Run]
button .btfr.quit -background #ffbbbb -activebackground #ffbbbb -text "Quit" -command exit
pack .btfr.run -side left -padx 100
pack .btfr.quit -side left
######################
Thanks to Ken I have implemented a frame in which I can add/delete buttons. The problem is that I need to have a scrollable frame otherwise the frame will keep growing and I won't be able to select the buttons at the bottom. This was solved by inserting the button frame inside a canvas. My problem now is that the scrollbar does not work, the frame keeps growing anyway. I have tried inserting
$cv configure -scrollregion [$cv bbox all] (see code below) in InsertFrame proc but this does not make any difference.
Please help!!!
#!/usr/local/bin/wish
#exec wish "$0" "$@"
#-----------------------------------------------------------------------------
##############################
frame .top -borderwidth 2
pack .top -fill x
#
#
#MENUS
#
menu .top.menuBar -tearoff 0
set f .top.menuBar.file
set fc .top.menuBar.func
set h .top.menuBar.help
set edit .top.menuBar.edit
#File menu
.top.menuBar add cascade -menu $f -label "File" -font {Helvetica 14 bold} -underline 0
menu $f -tearoff 1
$f add command -label "New" -font {Helvetica 12 bold} -underline 0 -command {}
$f add command -label "Open" -font {Helvetica 12 bold} -underline 0 -command {}
$f add command -label "Save" -font {Helvetica 12 bold} -underline 0 -command {}
$f add separator
$f add command -label "Exit" -font {Helvetica 12 bold} -underline 1 -command {exit} -accelerator "Meta-q"
#Edit
.top.menuBar add cascade -menu $edit -label "Edit" -font {Helvetica 14 bold} -underline 0
menu $edit -tearoff 1
$edit add command -label "Add before" -font {Helvetica 12 bold} -underline 0 -command {}
$edit add command -label "Add after" -font {Helvetica 12 bold} -underline 0 -command {}
$edit add command -label "Delete" -font {Helvetica 12 bold} -underline 0 -command {}
#Functions
.top.menuBar add cascade -menu $fc -label "Functions" -font {Helvetica 14 bold} -underline 0
menu $fc -tearoff 1
$fc add command -label "Import" -font {Helvetica 12 bold} -underline 0 -command {}
#help menu
.top.menuBar add cascade -menu $h -label "Help" -font {Helvetica 14 bold} -underline 0
menu $h -tearoff 1
$h add command -label "About.." -font {Helvetica 12 bold} -command {About} -underline 0
global f h fc edit
# bind accelerator keys
bind . <Meta-q> {exit}
# for frame select
bind . <ButtonPress-1> {
FrameSelect %W
}
. configure -menu .top.menuBar
# main window
#
wm title . "ZMAP MACRO BUILDER"
wm geometry . 400x300
wm minsize . 400 300
####
##
###
#function frame
set incfr 0
# Initialize a counter to help us create
# unique frame names on demand.
set frameCounter [incr incfr]
global incfr frameCounter
#
# Lower frame holds text output
#
#frame .logfr
#set log [text .logfr.log -width 50 -height 5 # -borderwidth 3 -relief sunken -setgrid true # -yscrollcommand {.logfr.scroll set} -font {courier 9}]
#scrollbar .logfr.scroll -command {.logfr.log yview}
#pack .logfr.scroll -side right -fill y
#pack .logfr.log -side left -fill both -expand true
#pack .logfr -side top -fill both -expand true
###########
# FUNCTIONS
############
###
# MAKE PROCESS FRAME
###
proc MakeFrame {w} {
global first
global cv
# make frame
puts "frame: $w"
frame $w -borderwidth 4
set item [$cv create window 1c 1c -window $w -anchor nw]
pack $w -side top -fill x
#checkbutton
checkbutton $w.cb -text "Empty " -variable dummy -command {} -padx 10
#button
button $w.b -text "Parameters..." -width 10 -command {} -padx 20
pack $w.cb $w.b -padx 5 -side left
update
if {$first } {
puts "in first"
set first 0
$cv configure -width [expr [winfo reqwidth $w.b] +10]
$cv configure -height [expr [winfo reqheight $w.b] * 5]
$cv configure -yscrollincrement [winfo reqheight $w.b]
set toto [expr [winfo reqwidth $w.b] +10]
puts $toto
set toto [expr [winfo reqheight $w.b] * 5]
puts $toto
}
$cv configure -scrollregion [$cv bbox all]
# $cv configure -scrollregion [$cv bbox $item]
# $cv yview 0
}
###############
proc mkScrollCanvas {w f width height } {
set c [canvas $w.c -width $width -height $height -bd 4 -relief ridge -yscrollcommand "$w.yscroll set"]
set s [scrollbar $w.yscroll -relief sunken -command "$w.c yview"]
set l [label $w.l -text "xxx"]
pack $l -side top -fill x -in $f
pack $s -side right -fill y -padx 1 -in $f
pack $c -side top -fill both -expand 1 -in $f
return $c
}
##################################
# FrameSelect
#
# Called by a binding to select a frame.
##################################
proc FrameSelect {w} {
global selected
puts "in FrameSelect"
# If the user clicked on a child widget
# rather than its parent frame, cycle up
# to the parent frame. Note that this
# simple algorithm *doesn't* allow for
# another frame to be nested in our
# containing frame. It also relies on you
# not changing the frame's class to
# anything other than "Frame" to work
# properly.
while {([winfo class $w] != "Frame"
&& ("$w" != "."} {
set w [winfo parent $w]
}
# "De-select" whatever is currently
# selected. This also handles "toggling"
# an already selected frame by clicking on
# it again.
if {[info exists selected(current)]} {
$selected(current) configure -relief $selected(relief)
}
#if {[info exists selected(current)]
#&& ($selected(current) == $w)} {
# The user clicked on the frame already
# selected. Simply "de-select" the frame
# and return.
#unset selected(current)
#return
#} else {
# Highlight the selected frame by
# changing its border to groove. To be
# visible, the frame must have its
# border width (-bd) set to a value
# greater than 2.
set selected(relief) [$w cget -relief]
set selected(current) $w
$w configure -relief groove
#}
}
# Create a symbolic bindtag called
# "selectable", that invokes our FrameSelect
# procedure in response to a left-click.
bind selectable <ButtonPress-1> {
FrameSelect %W
}
##################################
# InsertFrame
#
# Create a frame on demand. If another frame
# is selected, the new frame is packed
# before the selected frame; otherwise, the
# new frame is packed after all existing
# frames.
##################################
proc InsertFrame {} {
global selected
global frameCounter
global cv
set i [incr frameCounter]
#display first frame (default)
set f $cv.fr$i
puts $f
MakeFrame $f
if {[info exists selected(current)]} {
# If a frame is selected, insert the new
# frame in front of the selected one in
# the packing order.
pack $f -before $selected(current) -padx 2 -pady 2 -anchor w
} else {
# If no frame is selected, pack the new
# frame after all other frames.
pack $f -padx 2 -pady 2 -anchor w
}
$cv configure -scrollregion [$cv bbox all]
# Insert our "selectable" bindtag at the
# beginning of the bindtag path for the
# frame.
bindtags $f [linsert [bindtags $f] 0 selectable]
# Uncomment the following lines if you
# want the frame toggling binding active
# for the contents of the frame as well.
# bindtags $f.cb [linsert [bindtags $f.cb] 0 selectable]
# bindtags $f.b [linsert [bindtags $f.b] 0 selectable]
pack $f.cb -padx 2 -pady 2 -anchor w
pack $f.b -padx 2 -pady 2
}
##################################
# DeleteFrame
#
# Delete the currently selected frame. If no
# frame is selected, nothing happens.
##################################
proc DeleteFrame {} {
global selected
if {[info exists selected(current)]} {
destroy $selected(current)
unset selected(current)
}
}
# Define virtual events, which allows us to
# use mutiple bindings to perform the same
# task.
event add <<Insert>> <Control-KeyPress-a> <KeyPress-Insert>
event add <<Delete>> <Control-KeyPress-d> <KeyPress-Delete>
# Bind to the toplevel window, so that these
# bindings are active no matter which widget
# has focus.
bind . <<Insert>> InsertFrame
bind . <<Delete>> DeleteFrame
###### MAIN #########
#set first frame (default)
frame .f -height 1
pack .f
set first 1
set cv [mkScrollCanvas .f .f 0 0]
#display first frame (default)
MakeFrame $cv.fr1
#frames
# for buttons
frame .btfr -borderwidth 10
pack .btfr -fill x
#
# Action Buttons
#
set but [button .btfr.run -background #88ff88 -activebackground #88ff88 -text "Run" -command Run]
button .btfr.quit -background #ffbbbb -activebackground #ffbbbb -text "Quit" -command exit
pack .btfr.run -side left -padx 100
pack .btfr.quit -side left
######################