📄 tree.tcl
字号:
# ----------------------------------------------------------------------------# tree.tcl# This file is part of Unifix BWidget Toolkit# $Id: tree.tcl,v 1.35 2002/06/04 22:04:36 hobbs Exp $# ----------------------------------------------------------------------------# Index of commands:# - Tree::create# - Tree::configure# - Tree::cget# - Tree::insert# - Tree::itemconfigure# - Tree::itemcget# - Tree::bindText# - Tree::bindImage# - Tree::delete# - Tree::move# - Tree::reorder# - Tree::selection# - Tree::exists# - Tree::parent# - Tree::index# - Tree::nodes# - Tree::see# - Tree::opentree# - Tree::closetree# - Tree::edit# - Tree::xview# - Tree::yview# - Tree::_update_edit_size# - Tree::_destroy# - Tree::_see# - Tree::_recexpand# - Tree::_subdelete# - Tree::_update_scrollregion# - Tree::_cross_event# - Tree::_draw_node# - Tree::_draw_subnodes# - Tree::_update_nodes# - Tree::_draw_tree# - Tree::_redraw_tree# - Tree::_redraw_selection# - Tree::_redraw_idle# - Tree::_drag_cmd# - Tree::_drop_cmd# - Tree::_over_cmd# - Tree::_auto_scroll# - Tree::_scroll# ----------------------------------------------------------------------------namespace eval Tree { namespace eval Node { Widget::declare Tree::Node { {-text String "" 0} {-font TkResource "" 0 listbox} {-image TkResource "" 0 label} {-window String "" 0} {-fill TkResource black 0 {listbox -foreground}} {-data String "" 0} {-open Boolean 0 0} {-selectable Boolean 1 0} {-drawcross Enum auto 0 {auto allways never}} } } Widget::tkinclude Tree canvas .c \ remove { -insertwidth -insertbackground -insertborderwidth -insertofftime -insertontime -selectborderwidth -closeenough -confine -scrollregion -xscrollincrement -yscrollincrement -width -height } \ initialize { -relief sunken -borderwidth 2 -takefocus 1 -highlightthickness 1 -width 200 } Widget::declare Tree { {-deltax Int 10 0 "%d >= 0"} {-deltay Int 15 0 "%d >= 0"} {-padx Int 20 0 "%d >= 0"} {-background TkResource "" 0 listbox} {-selectbackground TkResource "" 0 listbox} {-selectforeground TkResource "" 0 listbox} {-selectcommand String "" 0} {-width TkResource "" 0 listbox} {-height TkResource "" 0 listbox} {-selectfill Boolean 0 0} {-showlines Boolean 1 0} {-linesfill TkResource black 0 {listbox -foreground}} {-linestipple TkResource "" 0 {label -bitmap}} {-redraw Boolean 1 0} {-opencmd String "" 0} {-closecmd String "" 0} {-dropovermode Flag "wpn" 0 "wpn"} {-bg Synonym -background} } DragSite::include Tree "TREE_NODE" 1 DropSite::include Tree { TREE_NODE {copy {} move {}} } Widget::addmap Tree "" .c {-deltay -yscrollincrement} # Trees on windows have a white (system window) background if { $::tcl_platform(platform) == "windows" } { option add *Tree.c.background SystemWindow widgetDefault option add *TreeNode.fill SystemWindowText widgetDefault } bind TreeSentinalStart <Button-1> { if { $::Tree::sentinal(%W) } { set ::Tree::sentinal(%W) 0 break } } bind TreeSentinalEnd <Button-1> { set ::Tree::sentinal(%W) 0 } bind TreeFocus <Button-1> [list focus %W] proc ::Tree { path args } { return [eval Tree::create $path $args] } proc use {} {} variable _edit}# ----------------------------------------------------------------------------# Command Tree::create# ----------------------------------------------------------------------------proc Tree::create { path args } { variable $path upvar 0 $path data Widget::init Tree $path $args set ::Tree::sentinal($path.c) 0 set data(root) {{}} set data(selnodes) {} set data(upd,level) 0 set data(upd,nodes) {} set data(upd,afterid) "" set data(dnd,scroll) "" set data(dnd,afterid) "" set data(dnd,selnodes) {} set data(dnd,node) "" frame $path -class Tree -bd 0 -highlightthickness 0 -relief flat \ -takefocus 0 # For 8.4+ we don't want to inherit the padding catch {$path configure -padx 0 -pady 0} eval canvas $path.c [Widget::subcget $path .c] -xscrollincrement 8 bindtags $path.c [list TreeSentinalStart TreeFocus $path.c Canvas \ [winfo toplevel $path] all TreeSentinalEnd] pack $path.c -expand yes -fill both $path.c bind cross <ButtonPress-1> [list Tree::_cross_event $path] # Added by ericm@scriptics.com # These allow keyboard traversal of the tree bind $path.c <KeyPress-Up> "Tree::_keynav up $path" bind $path.c <KeyPress-Down> "Tree::_keynav down $path" bind $path.c <KeyPress-Right> "Tree::_keynav right $path" bind $path.c <KeyPress-Left> "Tree::_keynav left $path" bind $path.c <KeyPress-space> "+Tree::_keynav space $path" # These allow keyboard control of the scrolling bind $path.c <Control-KeyPress-Up> "$path.c yview scroll -1 units" bind $path.c <Control-KeyPress-Down> "$path.c yview scroll 1 units" bind $path.c <Control-KeyPress-Left> "$path.c xview scroll -1 units" bind $path.c <Control-KeyPress-Right> "$path.c xview scroll 1 units" # ericm@scriptics.com bind $path <Configure> "Tree::_update_scrollregion $path" bind $path <Destroy> "Tree::_destroy $path" bind $path <FocusIn> [list after idle {BWidget::refocus %W %W.c}] DragSite::setdrag $path $path.c Tree::_init_drag_cmd \ [Widget::cget $path -dragendcmd] 1 DropSite::setdrop $path $path.c Tree::_over_cmd Tree::_drop_cmd 1 rename $path ::$path:cmd proc ::$path { cmd args } "return \[eval Tree::\$cmd $path \$args\]" set w [Widget::cget $path -width] set h [Widget::cget $path -height] set dy [Widget::cget $path -deltay] $path.c configure -width [expr {$w*8}] -height [expr {$h*$dy}] # ericm # Bind <Button-1> to select the clicked node -- no reason not to, right? Tree::bindText $path <Button-1> "$path selection set" Tree::bindImage $path <Button-1> "$path selection set" # Add sentinal bindings for double-clicking on items, to handle the # gnarly Tk bug wherein: # ButtonClick # ButtonClick # On a canvas item translates into button click on the item, button click # on the canvas, double-button on the item, single button click on the # canvas (which can happen if the double-button on the item causes some # other event to be handled in between when the button clicks are examined # for the canvas) $path.c bind TreeItemSentinal <Double-Button-1> \ "set ::Tree::sentinal($path.c) 1" # ericm return $path}# ----------------------------------------------------------------------------# Command Tree::configure# ----------------------------------------------------------------------------proc Tree::configure { path args } { variable $path upvar 0 $path data set res [Widget::configure $path $args] set ch1 [expr {[Widget::hasChanged $path -deltax val] | [Widget::hasChanged $path -deltay dy] | [Widget::hasChanged $path -padx val] | [Widget::hasChanged $path -showlines val]}] set ch2 [expr {[Widget::hasChanged $path -selectbackground val] | [Widget::hasChanged $path -selectforeground val]}] if { [Widget::hasChanged $path -linesfill fill] | [Widget::hasChanged $path -linestipple stipple] } { $path.c itemconfigure line -fill $fill -stipple $stipple $path.c itemconfigure cross -foreground $fill } if { $ch1 } { _redraw_idle $path 3 } elseif { $ch2 } { _redraw_idle $path 1 } if { [Widget::hasChanged $path -height h] } { $path.c configure -height [expr {$h*$dy}] } if { [Widget::hasChanged $path -width w] } { $path.c configure -width [expr {$w*8}] } if { [Widget::hasChanged $path -redraw bool] && $bool } { set upd $data(upd,level) set data(upd,level) 0 _redraw_idle $path $upd } set force [Widget::hasChanged $path -dragendcmd dragend] DragSite::setdrag $path $path.c Tree::_init_drag_cmd $dragend $force DropSite::setdrop $path $path.c Tree::_over_cmd Tree::_drop_cmd return $res}# ----------------------------------------------------------------------------# Command Tree::cget# ----------------------------------------------------------------------------proc Tree::cget { path option } { return [Widget::cget $path $option]}# ----------------------------------------------------------------------------# Command Tree::insert# ----------------------------------------------------------------------------proc Tree::insert { path index parent node args } { variable $path upvar 0 $path data if { [info exists data($node)] } { return -code error "node \"$node\" already exists" } if { ![info exists data($parent)] } { return -code error "node \"$parent\" does not exist" } Widget::init Tree::Node $path.$node $args if { ![string compare $index "end"] } { lappend data($parent) $node } else { incr index set data($parent) [linsert $data($parent) $index $node] } set data($node) [list $parent] if { ![string compare $parent "root"] } { _redraw_idle $path 3 } elseif { [visible $path $parent] } { # parent is visible... if { [Widget::getMegawidgetOption $path.$parent -open] } { # ...and opened -> redraw whole _redraw_idle $path 3 } else { # ...and closed -> redraw cross lappend data(upd,nodes) $parent 8 _redraw_idle $path 2 } } return $node}# ----------------------------------------------------------------------------# Command Tree::itemconfigure# ----------------------------------------------------------------------------proc Tree::itemconfigure { path node args } { variable $path upvar 0 $path data if { ![string compare $node "root"] || ![info exists data($node)] } { return -code error "node \"$node\" does not exist" } set result [Widget::configure $path.$node $args] if { [visible $path $node] } { set lopt {} set flag 0 foreach opt {-window -image -drawcross -font -text -fill} { set flag [expr {$flag << 1}] if { [Widget::hasChanged $path.$node $opt val] } { set flag [expr {$flag | 1}] } } if { [Widget::hasChanged $path.$node -open val] } { if {[llength $data($node)] > 1} { # node have subnodes - full redraw _redraw_idle $path 3 } else { # force a redraw of the plus/minus sign set flag [expr {$flag | 8}] } } if { $data(upd,level) < 3 && $flag } { if { [set idx [lsearch $data(upd,nodes) $node]] == -1 } { lappend data(upd,nodes) $node $flag } else { incr idx set flag [expr {[lindex $data(upd,nodes) $idx] | $flag}] set data(upd,nodes) [lreplace $data(upd,nodes) $idx $idx $flag] } _redraw_idle $path 2 } } return $result}# ----------------------------------------------------------------------------# Command Tree::itemcget# ----------------------------------------------------------------------------proc Tree::itemcget { path node option } { # Instead of upvar'ing $path as data for this test, just directly refer to # it, as that is faster. if { ![string compare $node "root"] || \ ![info exists ::Tree::${path}($node)] } { return -code error "node \"$node\" does not exist" } return [Widget::cget $path.$node $option]}# ----------------------------------------------------------------------------# Command Tree::bindText# ----------------------------------------------------------------------------proc Tree::bindText { path event script } { if { $script != "" } { $path.c bind "node" $event \ "$script \[Tree::_get_node_name $path current 2\]" } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -