⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 combobox.tcl

📁 windows下的GDB insight前端
💻 TCL
📖 第 1 页 / 共 5 页
字号:
    # import the widgets and options arrays into this proc so    # we don't have to use fully qualified names, which is a    # pain.    upvar ::combobox::${w}::widgets widgets    upvar ::combobox::${w}::options options    # this is our widget -- a frame of class Combobox. Naturally,    # it will contain other widgets. We create it here because    # we need it in order to set some default options.    set widgets(this)   [frame  $w -class Combobox -takefocus 0]    set widgets(entry)  [entry  $w.entry -takefocus 1]    set widgets(button) [label  $w.button -takefocus 0]     # this defines all of the default options. We get the    # values from the option database. Note that if an array    # value is a list of length one it is an alias to another    # option, so we just ignore it    foreach name [array names widgetOptions] {	if {[llength $widgetOptions($name)] == 1} continue	set optName  [lindex $widgetOptions($name) 0]	set optClass [lindex $widgetOptions($name) 1]	set value [option get $w $optName $optClass]	set options($name) $value    }    # a couple options aren't available in earlier versions of    # tcl, so we'll set them to sane values. For that matter, if    # they exist but are empty, set them to sane values.    if {[string length $options(-disabledforeground)] == 0} {        set options(-disabledforeground) $options(-foreground)    }    if {[string length $options(-disabledbackground)] == 0} {        set options(-disabledbackground) $options(-background)    }    # if -value is set to null, we'll remove it from our    # local array. The assumption is, if the user sets it from    # the option database, they will set it to something other    # than null (since it's impossible to determine the difference    # between a null value and no value at all).    if {[info exists options(-value)] \	    && [string length $options(-value)] == 0} {	unset options(-value)    }    # we will later rename the frame's widget proc to be our    # own custom widget proc. We need to keep track of this    # new name, so we'll define and store it here...    set widgets(frame) ::combobox::${w}::$w    # gotta do this sooner or later. Might as well do it now    pack $widgets(button) -side right -fill y    -expand no    pack $widgets(entry)  -side left  -fill both -expand yes    # I should probably do this in a catch, but for now it's    # good enough... What it does, obviously, is put all of    # the option/values pairs into an array. Make them easier    # to handle later on...    array set options $args    # now, the dropdown list... the same renaming nonsense    # must go on here as well...    set widgets(dropdown)   [toplevel  $w.top]    set widgets(listbox) [listbox   $w.top.list]    set widgets(vsb)     [scrollbar $w.top.vsb]    pack $widgets(listbox) -side left -fill both -expand y    # fine tune the widgets based on the options (and a few    # arbitrary values...)    # NB: we are going to use the frame to handle the relief    # of the widget as a whole, so the entry widget will be     # flat. This makes the button which drops down the list    # to appear "inside" the entry widget.    $widgets(vsb) configure \	    -borderwidth 1 \	    -command "$widgets(listbox) yview" \	    -highlightthickness 0    $widgets(button) configure \	    -background $options(-buttonbackground) \	    -highlightthickness 0 \	    -borderwidth $options(-elementborderwidth) \	    -relief raised \	    -width [expr {[winfo reqwidth $widgets(vsb)] - 2}]    $widgets(entry) configure \	    -borderwidth 0 \	    -relief flat \	    -highlightthickness 0     $widgets(dropdown) configure \	    -borderwidth $options(-elementborderwidth) \	    -relief sunken    $widgets(listbox) configure \	    -selectmode browse \	    -background [$widgets(entry) cget -bg] \	    -yscrollcommand "$widgets(vsb) set" \	    -exportselection false \	    -borderwidth 0#    trace variable ::combobox::${w}::entryTextVariable w \#	    [list ::combobox::EntryTrace $w]	    # do some window management foo on the dropdown window    wm overrideredirect $widgets(dropdown) 1    wm transient        $widgets(dropdown) [winfo toplevel $w]    wm group            $widgets(dropdown) [winfo parent $w]    wm resizable        $widgets(dropdown) 0 0    wm withdraw         $widgets(dropdown)        # this moves the original frame widget proc into our    # namespace and gives it a handy name    rename ::$w $widgets(frame)    # now, create our widget proc. Obviously (?) it goes in    # the global namespace. All combobox widgets will actually    # share the same widget proc to cut down on the amount of    # bloat.     proc ::$w {command args} \        "eval ::combobox::WidgetProc $w \$command \$args"    # ok, the thing exists... let's do a bit more configuration.     if {[catch "::combobox::Configure [list $widgets(this)] [array get options]" error]} {	catch {destroy $w}	error "internal error: $error"    }    return ""}# ::combobox::HandleEvent --##    this proc handles events from the entry widget that we want#    handled specially (typically, to allow navigation of the list#    even though the focus is in the entry widget)## Arguments:##    w       widget pathname#    event   a string representing the event (not necessarily an#            actual event)#    args    additional arguments required by particular eventsproc ::combobox::HandleEvent {w event args} {    upvar ::combobox::${w}::widgets  widgets    upvar ::combobox::${w}::options  options    upvar ::combobox::${w}::oldValue oldValue    # for all of these events, if we have a special action we'll    # do that and do a "return -code break" to keep additional     # bindings from firing. Otherwise we'll let the event fall    # on through.     switch $event {        "<MouseWheel>" {	    if {[winfo ismapped $widgets(dropdown)]} {                set D [lindex $args 0]                # the '120' number in the following expression has                # it's genesis in the tk bind manpage, which suggests                # that the smallest value of %D for mousewheel events                # will be 120. The intent is to scroll one line at a time.                $widgets(listbox) yview scroll [expr {-($D/120)}] units            }        } 	"<Any-KeyPress>" {	    # if the widget is editable, clear the selection. 	    # this makes it more obvious what will happen if the 	    # user presses <Return> (and helps our code know what	    # to do if the user presses return)	    if {$options(-editable)} {		$widgets(listbox) see 0		$widgets(listbox) selection clear 0 end		$widgets(listbox) selection anchor 0		$widgets(listbox) activate 0	    }	}	"<FocusIn>" {	    set oldValue [$widgets(entry) get]	}	"<FocusOut>" {	    if {![winfo ismapped $widgets(dropdown)]} {		# did the value change?		set newValue [$widgets(entry) get]		if {$oldValue != $newValue} {		    CallCommand $widgets(this) $newValue		}	    }	}	"<1>" {	    set editable [::combobox::GetBoolean $options(-editable)]	    if {!$editable} {		if {[winfo ismapped $widgets(dropdown)]} {		    $widgets(this) close		    return -code break;		} else {		    if {$options(-state) != "disabled"} {			$widgets(this) open			return -code break;		    }		}	    }	}	"<Double-1>" {	    if {$options(-state) != "disabled"} {		$widgets(this) toggle		return -code break;	    }	}	"<Tab>" {	    if {[winfo ismapped $widgets(dropdown)]} {		::combobox::Find $widgets(this) 0		return -code break;	    } else {		::combobox::SetValue $widgets(this) [$widgets(this) get]	    }	}	"<Escape>" {#	    $widgets(entry) delete 0 end#	    $widgets(entry) insert 0 $oldValue	    if {[winfo ismapped $widgets(dropdown)]} {		$widgets(this) close		return -code break;	    }	}	"<Return>" {	    # did the value change?	    set newValue [$widgets(entry) get]	    if {$oldValue != $newValue} {		CallCommand $widgets(this) $newValue	    }	    if {[winfo ismapped $widgets(dropdown)]} {		::combobox::Select $widgets(this) \			[$widgets(listbox) curselection]		return -code break;	    } 	}	"<Next>" {	    $widgets(listbox) yview scroll 1 pages	    set index [$widgets(listbox) index @0,0]	    $widgets(listbox) see $index	    $widgets(listbox) activate $index	    $widgets(listbox) selection clear 0 end	    $widgets(listbox) selection anchor $index	    $widgets(listbox) selection set $index	}	"<Prior>" {	    $widgets(listbox) yview scroll -1 pages	    set index [$widgets(listbox) index @0,0]	    $widgets(listbox) activate $index	    $widgets(listbox) see $index	    $widgets(listbox) selection clear 0 end	    $widgets(listbox) selection anchor $index	    $widgets(listbox) selection set $index	}	"<Down>" {	    if {[winfo ismapped $widgets(dropdown)]} {		::combobox::tkListboxUpDown $widgets(listbox) 1		return -code break;	    } else {		if {$options(-state) != "disabled"} {		    $widgets(this) open		    return -code break;		}	    }	}	"<Up>" {	    if {[winfo ismapped $widgets(dropdown)]} {		::combobox::tkListboxUpDown $widgets(listbox) -1		return -code break;	    } else {		if {$options(-state) != "disabled"} {		    $widgets(this) open		    return -code break;		}	    }	}    }    return ""}# ::combobox::DestroyHandler {w} --# #    Cleans up after a combobox 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 ::combobox::DestroyHandler {w} {    catch {	# if the widget actually being destroyed is of class Combobox,	# remove the namespace and associated proc.	if {[string compare [winfo class $w] "Combobox"] == 0} {	    # delete the namespace and the proc which represents	    # our widget	    namespace delete ::combobox::$w	    rename $w {}	}       }    return ""}# ::combobox::Find##    finds something in the listbox that matches the pattern in the#    entry widget and selects it##    N.B. I'm not convinced this is working the way it ought to. It#    works, but is the behavior what is expected? I've also got a gut#    feeling that there's a better way to do this, but I'm too lazy to#    figure it out...## Arguments:##    w      widget pathname#    exact  boolean; if true an exact match is desired## Returns:##    Empty stringproc ::combobox::Find {w {exact 0}} {    upvar ::combobox::${w}::widgets widgets    upvar ::combobox::${w}::options options    ## *sigh* this logic is rather gross and convoluted. Surely    ## there is a more simple, straight-forward way to implement    ## all this. As the saying goes, I lack the time to make it    ## shorter...    # use what is already in the entry widget as a pattern    set pattern [$widgets(entry) get]    if {[string length $pattern] == 0} {	# clear the current selection	$widgets(listbox) see 0	$widgets(listbox) selection clear 0 end	$widgets(listbox) selection anchor 0	$widgets(listbox) activate 0	return    }    # we're going to be searching this list...    set list [$widgets(listbox) get 0 end]    # if we are doing an exact match, try to find,    # well, an exact match    set exactMatch -1    if {$exact} {	set exactMatch [lsearch -exact $list $pattern]    }    # search for it. We'll try to be clever and not only    # search for a match for what they typed, but a match for    # something close to what they typed. We'll keep removing one    # character at a time from the pattern until we find a match    # of some sort.    set index -1    while {$index == -1 && [string length $pattern]} {	set index [lsearch -glob $list "$pattern*"]	if {$index == -1} {	    regsub {.$} $pattern {} pattern	}    }    # this is the item that most closely matches...    set thisItem [lindex $list $index]    # did we find a match? If so, do some additional munging...    if {$index != -1} {	# we need to find the part of the first item that is 	# unique WRT the second... I know there's probably a	# simpler way to do this... 	set nextIndex [expr {$index + 1}]	set nextItem [lindex $list $nextIndex]	# we don't really need to do much if the next	# item doesn't match our pattern...	if {[string match $pattern* $nextItem]} {	    # ok, the next item matches our pattern, too	    # now the trick is to find the first character	    # where they *don't* match...	    set marker [string length $pattern]	    while {$marker <= [string length $pattern]} {		set a [string index $thisItem $marker]		set b [string index $nextItem $marker]		if {[string compare $a $b] == 0} {		    append pattern $a		    incr marker		} else {		    break		}	    }	} else {	    set marker [string length $pattern]	}	    } else {	set marker end	set index 0    }    # ok, we know the pattern and what part is unique;    # update the entry widget and listbox appropriately

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -