The searchcolumn subcommand was added in Tablelist
version 5.3. It is often used together with the
-populatecommand configuration option, introduced in
Tablelist version 5.4. Here is a partly abbreviated version of the
subcommand's description in the reference manual:
pathName searchcolumn columnIndex pattern ?options?This subcommand searches the elements of the column given by
columnIndexto see if one of them matchespattern. If a match is found, the row index of the first matching element is returned as result (unless the option-allis specified). If not, the return value is-1. One or more of the following options may be specified to control the search:
-allChanges the result to be the list of all matching row indices, which will be in numeric order (or in reverse numeric order when used with the -backwardsoption).
-backwardsThe search will proceed backward through the given column's elements.
-check commandSpecifies an additional condition to be fulfilled by the matching elements. ...
-descendSearch the elements of the specified column in all descendants of the tree node given by the -parentoption. ...
-exactThe matching element(s) must be identical to the literal string pattern.
-formattedExamine the formatted versions of the elements rather than the internal cell values.
-globTreat patternas a glob-style pattern and match it against the elements using the same rules as thestring matchcommand.
-nocaseCauses comparisons to be handled in a case-insensitive manner. Has no effect if combined with the -numericoption.
-notThis option negates the sense of the match, ...
-numericThe elements are to be compared to patternas integer or floating-point values, using the==comparison operator. This option is only meaningful when used with-exact.
-parent nodeIndexThis option restricts the search to the children (or descendants, when used with -descend) of the tree node given bynodeIndex. The default parent isroot.
-regexpTreat patternas a regular expression and match it against the elements using the rules described in there_syntaxreference page.
-start indexThe elements of the specified column are to be searched (forwards or backwards) starting at the row given by index. ...If all matching style options
-exact,-glob, and-regexpare omitted then the matching style defaults to-glob. If more than one of them is specified, the last matching style given takes precedence.Before examining the children (or descendants, when used with the
-descendoption) of a row whose children have not been inserted yet, the command specified as the value of the-populatecommandoption (if any) is automatically concatenated with the name of the tablelist widget and the row index, and the resulting script is evaluated in the global scope. This enables you to insert the children on demand, just before searching them for the specified pattern.
The following example is an extended version of the demo script
dirViewer_tile.tcl. The pop-up menu within the tablelist
widget displaying the contents of a directory has a second command entry
Search for Pattern..., which opens a dialog for entering the data
needed for building the arguments to be passed to the
searchcolumn subcommand:
proc displayContents dir {
#
# Create a scrolled tablelist widget with 3 dynamic-
# width columns and interactive sort capability
#
set tf .tf
ttk::frame $tf -class ScrollArea
set tbl $tf.tbl
set vsb $tf.vsb
set hsb $tf.hsb
tablelist::tablelist $tbl \
-columns {0 "Name" left
0 "Size" right
0 "Date Modified" left} \
-expandcommand expandCmd -collapsecommand collapseCmd \
-xscrollcommand [list $hsb set] -yscrollcommand [list $vsb set] \
-movablecolumns no -showseparators yes -height 18 -width 80 \
-populatecommand populateCmd
. . .
#
# Create a pop-up menu with 2 command entries; bind the script
# associated with its first entry to the <Double-1> event, too
#
set menu .menu
menu $menu -tearoff no
foreach {label cmd} {"Display Contents" putContentsOfSelFolder
"Search for Pattern..." openSearchDlgForSelFolder} {
$menu add command -label $label -command [list $cmd $tbl]
}
set bodyTag [$tbl bodytag]
bind $bodyTag <<Button3>> [bind TablelistBody <Button-1>]
bind $bodyTag <<Button3>> +[bind TablelistBody <ButtonRelease-1>]
bind $bodyTag <<Button3>> +[list postPopupMenu %X %Y]
bind $bodyTag <Double-1> [list putContentsOfSelFolder $tbl]
. . .
#
# Populate the tablelist with the contents of the given directory
#
$tbl sortbycolumn 0
putContents $dir $tbl root
}
The procedure populateCmd, specified as the value of
the -populatecommand configuration option, will be
invoked automatically if (and only if) the searchcolumn
subcommand has to examine the children of a tablelist item and these children
are still unknown. In the presence of the -descend
subcommand option, this will be performed recursively As described in
the reference manual, the populateCmd procedure should
just insert the children of the row in question, without expanding the node
or changing its appearance in any other way. In our example, these
children correspond to the contents of the directory whose leaf name is
displayed in the first cell of the specified row:
proc populateCmd {tbl row} {
set dir [$tbl rowattrib $row pathName]
putContents $dir $tbl $row
}
The procedure openSearchDlgForSelFolder, associated
with the Search for Pattern... pop-up menu entry, creates a dialog
window containing:
findPattern procedure associated with the Find
button;The procedure uses, among others, the
mentry::dateTimeMentry command from the Mentry package
for creating two multi-entry widgets that hold the modification date
interval and the Wcb package for a strait-forward implementation of the text
widget's read-only behavior:
proc openSearchDlgForSelFolder tbl {
set row [$tbl curselection]
set key [$tbl getkeys $row]
set top .top$key
if {[winfo exists $top]} {
raise $top
return ""
}
toplevel $top
set dir [$tbl rowattrib $row pathName]
wm title $top "Search in Directory \"[file nativename $dir]\""
. . .
#
# "Modification Date" checkbuttons and mentry widgets
#
set lfLastModDateTime [ttk::labelframe $f.lfLastModDateTime -text \
"Modification Date"]
set ::data($key-useMinDateTime) 0
set ::data($key-useMaxDateTime) 0
set ckMinDateTime [ttk::checkbutton $lfLastModDateTime.ckMinDateTime -text \
"After:" -variable data($key-useMinDateTime)]
set meMinDateTime [mentry::dateTimeMentry \
$lfLastModDateTime.meMinDateTime YmdHM - : \
-justify center -background white]
set ckMaxDateTime [ttk::checkbutton $lfLastModDateTime.ckMaxDateTime -text \
"Before:" -variable data($key-useMaxDateTime)]
set meMaxDateTime [mentry::dateTimeMentry \
$lfLastModDateTime.meMaxDateTime YmdHM - : \
-justify center -background white]
set maxClock [clock seconds]
set minClock [expr {$maxClock - 24*60*60}]
mentry::putClockVal $minClock $meMinDateTime
mentry::putClockVal $maxClock $meMaxDateTime
. . .
#
# "Find" and "Close" buttons
#
set fBtns [ttk::frame $f.fBtns]
set bFind [ttk::button $fBtns.bFind -text "Find" -default active \
-command [list findPattern $tbl $key]]
set bClose [ttk::button $fBtns.bClose -text "Close" -default normal \
-command [list destroy $top]]
. . .
#
# Readonly text widget displaying the search command
#
set tCmd [text $f.tCmd -background white -height 2 -width 70 -wrap word \
-highlightthickness 0 -insertwidth 0]
wcb::callback $tCmd before insert cancelInput
wcb::callback $tCmd before delete cancelInput
proc cancelInput {w idx args} { wcb::cancel }
set ::data($key-tCmd) $tCmd
#
# Scrollable tablelist widget displaying the search result
#
set fResult $f.fResult
ttk::frame $fResult -class ScrollArea
set resTbl $fResult.tbl
set vsb $fResult.vsb
set hsb $fResult.hsb
tablelist::tablelist $resTbl \
-columns {0 "Path" left
0 "Size" right
0 "Date Modified" left} \
-xscrollcommand [list $hsb set] -yscrollcommand [list $vsb set] \
-movablecolumns no -showseparators yes -height 12 -width 70
. . .
}
The findPattern procedure associated with the
Find button of the dialog described above builds the search command
from the data entered by the user, evaluates it, and displays the data of the
matching items in the search result tablelist widget :
proc findPattern {tbl key} {
. . .
#
# Build, show, and evaluate the search command
#
set searchCmd [list $tbl searchcolumn 0 $::data($key-pattern) \
-parent k$key -all -formatted $::data($key-style)]
if {$::data($key-descend)} {
lappend searchCmd -descend
}
if {$::data($key-noCase)} {
lappend searchCmd -nocase
}
if {$useMinDateTime || $useMaxDateTime} {
set checkCmd [list checkDateTime $minDateTime $maxDateTime]
lappend searchCmd -check $checkCmd
}
_$tCmd insert end $searchCmd
update idletasks
set rowList [eval $searchCmd]
#
# Populate the search result tablelist with the data of the matching items
#
foreach row $rowList {
set item [$tbl get $row]
foreach {name size dateTime} $item {}
. . .
}
}