📄 widget.tcl
字号:
proc Widget::init { class path options } { upvar 0 ${class}::opt classopt upvar 0 ${class}::$path:opt pathopt upvar 0 ${class}::$path:mod pathmod upvar 0 ${class}::map classmap upvar 0 ${class}::$path:init pathinit if { [info exists pathopt] } { unset pathopt } if { [info exists pathmod] } { unset pathmod } # We prefer to use the actual widget for option db queries, but if it # doesn't exist yet, do the next best thing: create a widget of the # same class and use that. set fpath $path set rdbclass [string map [list :: ""] $class] if { ![winfo exists $path] } { set fpath ".#BWidgetClass#$class" if { ![winfo exists $fpath] } { frame $fpath -class $rdbclass } } foreach {option optdesc} [array get classopt] { set pathmod($option) 0 if { [info exists classmap($option)] } { continue } set type [lindex $optdesc 0] if { ![string compare $type "Synonym"] } { continue } if { ![string compare $type "TkResource"] } { set alt [lindex [lindex $optdesc 3] 1] } else { set alt "" } set optdb [lindex [_configure_option $option $alt] 0] set def [option get $fpath $optdb $rdbclass] if { [string length $def] } { set pathopt($option) $def } else { set pathopt($option) [lindex $optdesc 1] } } set Widget::_class($path) $class foreach {option value} $options { if { ![info exists classopt($option)] } { unset pathopt unset pathmod return -code error "unknown option \"$option\"" } set optdesc $classopt($option) set type [lindex $optdesc 0] if { ![string compare $type "Synonym"] } { set option [lindex $optdesc 1] set optdesc $classopt($option) set type [lindex $optdesc 0] } set pathopt($option) [$Widget::_optiontype($type) $option $value [lindex $optdesc 3]] set pathinit($option) $pathopt($option) }}# Bastien Chevreux (bach@mwgdna.com)## copyinit performs basically the same job as init, but it uses a# existing template to initialize its values. So, first a perferct copy# from the template is made just to be altered by any existing options# afterwards.# But this still saves time as the first initialization parsing block is# skipped.# As additional bonus, items that differ in just a few options can be# initialized faster by leaving out the options that are equal.# This function is currently used only by ListBox::multipleinsert, but other# calls should follow :)# ----------------------------------------------------------------------------# Command Widget::copyinit# ----------------------------------------------------------------------------proc Widget::copyinit { class templatepath path options } { upvar 0 ${class}::opt classopt \ ${class}::$path:opt pathopt \ ${class}::$path:mod pathmod \ ${class}::$path:init pathinit \ ${class}::$templatepath:opt templatepathopt \ ${class}::$templatepath:mod templatepathmod \ ${class}::$templatepath:init templatepathinit if { [info exists pathopt] } { unset pathopt } if { [info exists pathmod] } { unset pathmod } # We use the template widget for option db copying, but it has to exist! array set pathmod [array get templatepathmod] array set pathopt [array get templatepathopt] array set pathinit [array get templatepathinit] set Widget::_class($path) $class foreach {option value} $options { if { ![info exists classopt($option)] } { unset pathopt unset pathmod return -code error "unknown option \"$option\"" } set optdesc $classopt($option) set type [lindex $optdesc 0] if { ![string compare $type "Synonym"] } { set option [lindex $optdesc 1] set optdesc $classopt($option) set type [lindex $optdesc 0] } set pathopt($option) [$Widget::_optiontype($type) $option $value [lindex $optdesc 3]] set pathinit($option) $pathopt($option) }}# Widget::parseArgs --## Given a widget class and a command-line spec, cannonize and validate# the given options, and return a keyed list consisting of the # component widget and its masked portion of the command-line spec, and# one extra entry consisting of the portion corresponding to the # megawidget itself.## Arguments:# class widget class to parse for.# options command-line spec## Results:# result keyed list of portions of the megawidget and that segment of# the command line in which that portion is interested.proc Widget::parseArgs {class options} { upvar 0 ${class}::opt classopt upvar 0 ${class}::map classmap foreach {option val} $options { if { ![info exists classopt($option)] } { error "unknown option \"$option\"" } set optdesc $classopt($option) set type [lindex $optdesc 0] if { ![string compare $type "Synonym"] } { set option [lindex $optdesc 1] set optdesc $classopt($option) set type [lindex $optdesc 0] } if { ![string compare $type "TkResource"] } { # Make sure that the widget used for this TkResource exists Widget::_get_tkwidget_options [lindex [lindex $optdesc 3] 0] } set val [$Widget::_optiontype($type) $option $val [lindex $optdesc 3]] if { [info exists classmap($option)] } { foreach {subpath subclass realopt} $classmap($option) { lappend maps($subpath) $realopt $val } } else { lappend maps($class) $option $val } } return [array get maps]}# Widget::initFromODB --## Initialize a megawidgets options with information from the option# database and from the command-line arguments given.## Arguments:# class class of the widget.# path path of the widget -- should already exist.# options command-line arguments.## Results:# None.proc Widget::initFromODB {class path options} { upvar 0 ${class}::$path:opt pathopt upvar 0 ${class}::$path:mod pathmod upvar 0 ${class}::map classmap if { [info exists pathopt] } { unset pathopt } if { [info exists pathmod] } { unset pathmod } # We prefer to use the actual widget for option db queries, but if it # doesn't exist yet, do the next best thing: create a widget of the # same class and use that. set fpath [_get_window $class $path] set rdbclass [string map [list :: ""] $class] if { ![winfo exists $path] } { set fpath ".#BWidgetClass#$class" if { ![winfo exists $fpath] } { frame $fpath -class $rdbclass } } foreach {option optdesc} [array get ${class}::opt] { set pathmod($option) 0 if { [info exists classmap($option)] } { continue } set type [lindex $optdesc 0] if { ![string compare $type "Synonym"] } { continue } if { ![string compare $type "TkResource"] } { set alt [lindex [lindex $optdesc 3] 1] } else { set alt "" } set optdb [lindex [_configure_option $option $alt] 0] set def [option get $fpath $optdb $rdbclass] if { [string length $def] } { set pathopt($option) $def } else { set pathopt($option) [lindex $optdesc 1] } } set Widget::_class($path) $class array set pathopt $options}# ----------------------------------------------------------------------------# Command Widget::destroy# ----------------------------------------------------------------------------proc Widget::destroy { path } { variable _class set class $_class($path) upvar 0 ${class}::$path:opt pathopt upvar 0 ${class}::$path:mod pathmod upvar 0 ${class}::$path:init pathinit if {[info exists pathopt]} { unset pathopt } if {[info exists pathmod]} { unset pathmod } if {[info exists pathinit]} { unset pathinit }}# ----------------------------------------------------------------------------# Command Widget::configure# ----------------------------------------------------------------------------proc Widget::configure { path options } { set len [llength $options] if { $len <= 1 } { return [_get_configure $path $options] } elseif { $len % 2 == 1 } { return -code error "incorrect number of arguments" } variable _class variable _optiontype set class $_class($path) upvar 0 ${class}::opt classopt upvar 0 ${class}::map classmap upvar 0 ${class}::$path:opt pathopt upvar 0 ${class}::$path:mod pathmod set window [_get_window $class $path] foreach {option value} $options { if { ![info exists classopt($option)] } { return -code error "unknown option \"$option\"" } set optdesc $classopt($option) set type [lindex $optdesc 0] if { ![string compare $type "Synonym"] } { set option [lindex $optdesc 1] set optdesc $classopt($option) set type [lindex $optdesc 0] } if { ![lindex $optdesc 2] } { set newval [$_optiontype($type) $option $value [lindex $optdesc 3]] if { [info exists classmap($option)] } { set window [_get_window $class $window] foreach {subpath subclass realopt} $classmap($option) { if { [string length $subclass] } { set curval [${subclass}::cget $window$subpath $realopt] ${subclass}::configure $window$subpath $realopt $newval } else { set curval [$window$subpath cget $realopt] $window$subpath configure $realopt $newval } } } else { set curval $pathopt($option) set pathopt($option) $newval } set pathmod($option) [expr {![string equal $newval $curval]}] } } return {}}# ----------------------------------------------------------------------------# Command Widget::cget# ----------------------------------------------------------------------------proc Widget::cget { path option } { if { ![info exists ::Widget::_class($path)] } { return -code error "unknown widget $path" } set class $::Widget::_class($path) if { ![info exists ${class}::opt($option)] } { return -code error "unknown option \"$option\"" } set optdesc [set ${class}::opt($option)] set type [lindex $optdesc 0] if { ![string compare $type "Synonym"] } { set option [lindex $optdesc 1] } if { [info exists ${class}::map($option)] } { foreach {subpath subclass realopt} [set ${class}::map($option)] {break} set path "[_get_window $class $path]$subpath" return [$path cget $realopt] } upvar 0 ${class}::$path:opt pathopt set pathopt($option)}# ----------------------------------------------------------------------------# Command Widget::subcget# ----------------------------------------------------------------------------proc Widget::subcget { path subwidget } { set class $::Widget::_class($path) upvar 0 ${class}::$path:opt pathopt upvar 0 ${class}::map$subwidget submap upvar 0 ${class}::$path:init pathinit set result {} foreach realopt [array names submap] { if { [info exists pathinit($submap($realopt))] } { lappend result $realopt $pathopt($submap($realopt)) } } return $result}# ----------------------------------------------------------------------------# Command Widget::hasChanged# ----------------------------------------------------------------------------proc Widget::hasChanged { path option pvalue } { upvar $pvalue value set class $::Widget::_class($path) upvar 0 ${class}::$path:mod pathmod set value [Widget::cget $path $option] set result $pathmod($option) set pathmod($option) 0 return $result}proc Widget::hasChangedX { path option args } { set class $::Widget::_class($path) upvar 0 ${class}::$path:mod pathmod set result $pathmod($option) set pathmod($option) 0 foreach option $args { lappend result $pathmod($option) set pathmod($option) 0 } set result}# ----------------------------------------------------------------------------# Command Widget::setoption# ----------------------------------------------------------------------------proc Widget::setoption { path option value } {# variable _class# set class $_class($path)# upvar 0 ${class}::$path:opt pathopt# set pathopt($option) $value Widget::configure $path [list $option $value]}# ----------------------------------------------------------------------------# Command Widget::getoption# ----------------------------------------------------------------------------proc Widget::getoption { path option } {# set class $::Widget::_class($path)# upvar 0 ${class}::$path:opt pathopt# return $pathopt($option) return [Widget::cget $path $option]}# Widget::getMegawidgetOption --## Bypass the superfluous checks in cget and just directly peer at the# widget's data space. This is much more fragile than cget, so it # should only be used with great care, in places where speed is critical.## Arguments:# path widget to lookup options for.# option option to retrieve.## Results:# value option value.proc Widget::getMegawidgetOption {path option} { set class $::Widget::_class($path) upvar 0 ${class}::${path}:opt pathopt set pathopt($option)}# Widget::setMegawidgetOption --## Bypass the superfluous checks in cget and just directly poke at the# widget's data space. This is much more fragile than configure, so it # should only be used with great care, in places where speed is critical.## Arguments:# path widget to lookup options for.# option option to retrieve.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -