📄 mclistbox.wgt
字号:
-resizable {
if {[catch {
if {$value} {
set options($id:-resizable) 1
} else {
set options($id:-resizable) 0
}
} msg]} {
return -code error "expected boolean but got \"$value\""
}
}
-visible {
if {[catch {
if {$value} {
set options($id:-visible) 1
$widgets(text) configure -state normal
$widgets(text) window configure 1.$index -window $frame
$widgets(text) configure -state disabled
} else {
set options($id:-visible) 0
$widgets(text) configure -state normal
$widgets(text) window configure 1.$index -window {}
$widgets(text) configure -state disabled
}
InvalidateScrollbars $w
} msg]} {
return -code error "expected boolean but got \"$value\""
}
}
-position {
if {[string compare $value "start"] == 0} {
set position 0
} elseif {[string compare $value "end"] == 0} {
set position [expr {[llength $misc(columns)] -1}]
} else {
# ought to check for a legal value here, but I'm
# lazy
set position $value
}
if {$position >= [llength $misc(columns)]} {
set max [expr {[llength $misc(columns)] -1}]
return -code error "bad position; must be in the range of 0-$max"
}
# rearrange misc(columns) to reflect the new ordering
set current [lsearch -exact $misc(columns) $id]
set misc(columns) [lreplace $misc(columns) $current $current]
set misc(columns) [linsert $misc(columns) $position $id]
set frame $widgets(frame$id)
$widgets(text) configure -state normal
$widgets(text) window create 1.$position \
-window $frame -stretch 1
$widgets(text) configure -state disabled
}
}
}
}
# ::mclistbox::DestroyHandler {w} --
#
# Cleans up after a mclistbox widget is destroyed
#
# Arguments:
#
# w widget pathname
#
# Results:
#
# The namespace that was created for the widget is deleted,
# and the widget proc is removed.
proc ::mclistbox::DestroyHandler {w} {
# kill off any idle event we might have pending
if {[info exists ::mclistbox::${w}::misc(afterid)]} {
catch {
after cancel $::mclistbox::${w}::misc(afterid)
unset ::mclistbox::${w}::misc(afterid)
}
}
# if the widget actually being destroyed is of class Mclistbox,
# crush the namespace and kill the proc. Get it? Crush. Kill.
# Destroy. Heh. Danger Will Robinson! Oh, man! I'm so funny it
# brings tears to my eyes.
if {[string compare [winfo class $w] "Mclistbox"] == 0} {
namespace delete ::mclistbox::$w
rename $w {}
}
}
# ::mclistbox::MassageIndex --
#
# this proc massages indicies of the form @x,y such that
# the coordinates are relative to the first listbox rather
# than relative to the topmost frame.
#
# Arguments:
#
# w widget pathname
# index an index of the form @x,y
#
# Results:
#
# Returns a new index with translated coordinates. This index
# may be used directly by an internal listbox.
proc ::mclistbox::MassageIndex {w index} {
upvar ::mclistbox::${w}::widgets widgets
upvar ::mclistbox::${w}::misc misc
if {[regexp {@([0-9]+),([0-9]+)} $index matchvar x y]} {
set id [lindex $misc(columns) 0]
incr y -[winfo y $widgets(listbox$id)]
incr y -[winfo y $widgets(frame$id)]
incr x [winfo x $widgets(listbox$id)]
incr x [winfo x $widgets(frame$id)]
set index @${x},${y}
}
return $index
}
# ::mclistbox::WidgetProc --
#
# This gets uses as the widgetproc for an mclistbox widget.
# Notice where the widget is created and you'll see that the
# actual widget proc merely evals this proc with all of the
# arguments intact.
#
# Note that some widget commands are defined "inline" (ie:
# within this proc), and some do most of their work in
# separate procs. This is merely because sometimes it was
# easier to do it one way or the other.
#
# Arguments:
#
# w widget pathname
# command widget subcommand
# args additional arguments; varies with the subcommand
#
# Results:
#
# Performs the requested widget command
proc ::mclistbox::WidgetProc {w command args} {
variable widgetOptions
upvar ::mclistbox::${w}::widgets widgets
upvar ::mclistbox::${w}::options options
upvar ::mclistbox::${w}::misc misc
upvar ::mclistbox::${w}::columnID columnID
set command [::mclistbox::Canonize $w command $command]
# some commands have subcommands. We'll check for that here
# and mung the command and args so that we can treat them as
# distinct commands in the following switch statement
if {[string compare $command "column"] == 0} {
set subcommand [::mclistbox::Canonize $w "column command" \
[lindex $args 0]]
set command "$command-$subcommand"
set args [lrange $args 1 end]
} elseif {[string compare $command "label"] == 0} {
set subcommand [::mclistbox::Canonize $w "label command" \
[lindex $args 0]]
set command "$command-$subcommand"
set args [lrange $args 1 end]
}
set result ""
catch {unset priorSelection}
# here we go. Error checking be damned!
switch $command {
xview {
# note that at present, "xview <index>" is broken. I'm
# not even sure how to do it. Unless I attach our hidden
# listbox to the scrollbar and use it. Hmmm..... I'll
# try that later. (FIXME)
set result [eval {$widgets(text)} xview $args]
InvalidateScrollbars $w
}
yview {
if {[llength $args] == 0} {
# length of zero means to fetch the yview; we can
# get this from a single listbox
set result [$widgets(hiddenListbox) yview]
} else {
# if it's one argument, it's an index. We'll pass that
# index through the index command to properly translate
# @x,y indicies, and place the value back in args
if {[llength $args] == 1} {
set index [::mclistbox::MassageIndex $w [lindex $args 0]]
set args [list $index]
}
# run the yview command on every column.
foreach id $misc(columns) {
eval {$widgets(listbox$id)} yview $args
}
eval {$widgets(hiddenListbox)} yview $args
InvalidateScrollbars $w
set result ""
}
}
activate {
if {[llength $args] != 1} {
return -code error "wrong \# of args: should be $w activate index"
}
set index [::mclistbox::MassageIndex $w [lindex $args 0]]
foreach id $misc(columns) {
$widgets(listbox$id) activate $index
}
set result ""
}
bbox {
if {[llength $args] != 1} {
return -code error "wrong \# of args: should be $w bbox index"
}
# get a real index. This will adjust @x,y indicies
# to account for the label, if any.
set index [::mclistbox::MassageIndex $w [lindex $args 0]]
set id [lindex $misc(columns) 0]
# we can get the x, y, and height from the first
# column.
set bbox [$widgets(listbox$id) bbox $index]
if {[string length $bbox] == 0} {return ""}
foreach {x y w h} $bbox {}
# the x and y coordinates have to be adjusted for the
# fact that the listbox is inside a frame, and the
# frame is inside a text widget. All of those add tiny
# offsets. Feh.
incr y [winfo y $widgets(listbox$id)]
incr y [winfo y $widgets(frame$id)]
incr x [winfo x $widgets(listbox$id)]
incr x [winfo x $widgets(frame$id)]
# we can get the width by looking at the relative x
# coordinate of the right edge of the last column
set id [lindex $misc(columns) end]
set w [expr {[winfo width $widgets(frame$id)] + \
[winfo x $widgets(frame$id)]}]
set bbox [list $x $y [expr {$x + $w}] $h]
set result $bbox
}
label-bind {
# we are just too clever for our own good. (that's a
# polite way of saying this is more complex than it
# needs to be)
set id [lindex $args 0]
set index [CheckColumnID $w $id]
set args [lrange $args 1 end]
if {[llength $args] == 0} {
set result [bind $widgets(label$id)]
} else {
# when we create a binding, we'll actually have the
# binding run our own command with the user's command
# as an argument. This way we can do some sanity checks
# before running the command. So, when querying a binding
# we need to only return the user's code
set sequence [lindex $args 0]
if {[llength $args] == 1} {
set result [lindex [bind $widgets(label$id) $sequence] end]
} else {
# replace %W with our toplevel frame, then
# do the binding
set code [lindex $args 1]
regsub -all {%W} $code $w code
set result [bind $widgets(label$id) $sequence \
[list ::mclistbox::LabelEvent $w $id $code]]
}
}
}
column-add {
eval ::mclistbox::Column-add {$w} $args
AdjustColumns $w
set result ""
}
column-delete {
foreach id $args {
set index [CheckColumnID $w $id]
# remove the reference from our list of columns
set misc(columns) [lreplace $misc(columns) $index $index]
# whack the widget
destroy $widgets(frame$id)
# clear out references to the individual widgets
unset widgets(frame$id)
unset widgets(listbox$id)
unset widgets(label$id)
}
InvalidateScrollbars $w
set result ""
}
column-cget {
if {[llength $args] != 2} {
return -code error "wrong # of args: should be \"$w column cget name option\""
}
set id [::mclistbox::Canonize $w column [lindex $args 0]]
set option [lindex $args 1]
set data [::mclistbox::Column-configure $w $id $option]
set result [lindex $data 4]
}
column-configure {
set id [::mclistbox::Canonize $w column [lindex $args 0]]
set args [lrange $args 1 end]
set result [eval ::mclistbox::Column-configure {$w} {$id} $args]
}
column-names {
if {[llength $args] != 0} {
return -code error "wrong # of args: should be \"$w column names\""
}
set result $misc(columns)
}
column-nearest {
if {[llength $args] != 1} {
return -code error "wrong # of args: should be \"$w column nearest x\""
}
set x [lindex $args 0]
set tmp [$widgets(text) index @$x,0]
set tmp [split $tmp "."]
set index [lindex $tmp 1]
set result [lindex $misc(columns) $index]
}
cget {
if {[llength $args] != 1} {
return -code error "wrong # args: should be $w cget option"
}
set opt [::mclistbox::Canonize $w option [lindex $args 0]]
set result $options($opt)
}
configure {
set result [eval ::mclistbox::Configure {$w} $args]
}
itemconfigure {
set result [eval ::mclistbox::ItemConfigure {$w} $args]
}
curselection {
set id [lindex $misc(columns) 0]
set result [$widgets(listbox$id) curselection]
}
delete {
if {[llength $args] < 1 || [llength $args] > 2} {
return -code error "wrong \# of args: should be $w delete first ?last?"
}
# it's possible that the selection will change because
# of something we do. So, grab the current selection before
# we do anything. Just before returning we'll see if the
# selection has changed. If so, we'll call our selectcommand
if {$options(-selectcommand) != ""} {
set col0 [lindex $misc(columns) 0]
set priorSelection [$widgets(listbox$col0) curselection]
}
set index1 [::mclistbox::MassageIndex $w [lindex $args 0]]
if {[llength $args] == 2} {
set index2 [::mclistbox::MassageIndex $w [lindex $args 1]]
} else {
set index2 ""
}
# note we do an eval here to make index2 "disappear" if it
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -