The bug is not in Tablelist, but in the way you are using the binding tags.
In your listbox example you bind a script to the widget name, which
precedes the widget class binding tag "Listbox". Consequently, the
print_selection procedure will be invoked before the default bindings
for "Listbox" unselect all elements, except the last clicked one. Due
to this fact, the curselection listbox subcommand will return the
expected index list.
On the other hand, in your tablelist example you bind a script to the
binding tag "TablelistBody", which is used by the Tablelist
implementation in the default mouse and keyboard bindings for the
tablelist body, embedded images, and other auxiliary objects that have
this name in the list of their binding tags. In addition, due to the
"+" character starting your script, the print_selection procedure will
be invoked after the default binding script for this tag, which belongs
to the private part of the Tablelist implementation. Consequently, by
the time this procedure is called, all items except the last clicked one
will already be in unselected state, and thus the curselection tablelist
subcommand will return a list of length 1.
To make your 2nd script work like the 1st one, you have to replace the
binding tag "TablelistBody" with [.l bodypath] or [.l bodytag] (the
latter is the recommended choice). Here is the corrected version of the
script:
package req Tk
package req tablelist
tablelist::tablelist .l -columntitles {test} -selectmode extended
pack .l -expand 1 -fill both
bind [.l bodytag] <Button-1> [list print_selection %W]
.l insert end 1
.l insert end 2
.l insert end 3
.l insert end 4
proc print_selection {w} {
set tbl [tablelist::getTablelistPath $w]
puts "SELECTION: [$tbl curselection]"
}
In this example, the argument passed to the print_selection procedure
will be the body component of the tablelist widget whose name is
returned by the tablelist::getTablelistPath procedure.