• TCL Treeview issues

    From GeorgeB@21:1/5 to All on Sun Sep 18 12:28:08 2022
    Hello,

    Newbie here, and I'm having some difficulties with treeview in TCL.

    I'm working off a demo example from Active State TCL.

    1) I wondered if someone could help, I get the following error but don't know what to do to fix or how to fix.

    Error is invalid command error ERROR: invalid command name "populateTree"

    command bound to event: "populateTree .fc.tv.tree [.fc.tv.tree focus]"

    Code is below

    2) How do I get a selection from multiple items treeview to be saved in a variable.


    # temp dir to mimic Network dir
    set ::dir "C:/Dev"

    proc populateRoots {tree} {
    populateTree $tree [$tree insert {} end -text "Network File" \
    -values [list $::dir directory]]
    }

    ## Code to populate a node of the tree
    proc populateTree {tree node} {
    if {[$tree set $node type] ne "directory"} {
    return
    }
    set path [$tree set $node fullpath]
    $tree delete [$tree children $node]
    foreach f [lsort -dictionary [glob -nocomplain -dir $path *]] {
    set type [file type $f]
    set id [$tree insert $node end -text [file tail $f] \
    -values [list $f $type]]
    if {$type eq "directory"} {
    ## Make it so that this node is openable
    $tree insert $id 0 -text dummy ;# a dummy
    $tree item $id -text [file tail $f]/
    } elseif {$type eq "file"} {
    set size [file size $f]
    set ttime [file mtime $f]
    ## Format the file size nicely
    if {$size >= 1024*1024*1024} {
    set size [format %.1f\ GB [expr {$size/1024/1024/1024.}]]
    } elseif {$size >= 1024*1024} {
    set size [format %.1f\ MB [expr {$size/1024/1024.}]]
    } elseif {$size >= 1024} {
    set size [format %.1f\ kB [expr {$size/1024.}]]
    } else {
    append size " bytes"
    }
    $tree set $id size $size
    }
    }

    # Stop this code from rerunning on the current node
    $tree set $node type processedDirectory
    }

    # ## Create the tree and set it up


    ttk::treeview $tw.tree -columns {fullpath type size date time} -displaycolumns {size date time} \
    -yscroll "$tw.vsb set" -xscroll "$tw.hsb set"
    ttk::scrollbar $tw.vsb -orient vertical -command "$tw.tree yview"
    ttk::scrollbar $tw.hsb -orient horizontal -command "$tw.tree xview"
    $tw.tree heading \#0 -text "Directory Structure"
    $tw.tree heading size -text "File Size"
    $tw.tree column size -stretch 0 -width 70
    populateRoots $tw.tree
    bind $tw.tree <<TreeviewOpen>> {populateTree %W [%W focus]}

    # ## Arrange the tree and its scrollbars in the toplevel
    lower [ttk::frame $tw.dummy]
    pack $tw.dummy -fill both -expand 1
    grid $tw.tree $tw.vsb -sticky nsew -in $tw.dummy
    grid $tw.hsb -sticky nsew -in $tw.dummy
    grid columnconfigure $tw.dummy 0 -weight 1
    grid rowconfigure $tw.dummy 0 -weight 1


    Thank you in advance

    George

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ralf Fassel@21:1/5 to All on Mon Sep 19 12:01:27 2022
    * GeorgeB <[email protected]>
    | Hello,

    | Newbie here, and I'm having some difficulties with treeview in TCL.

    | I'm working off a demo example from Active State TCL.

    | 1) I wondered if someone could help, I get the following error but don't know what to do to fix or how to fix.

    | Error is invalid command error ERROR: invalid command name "populateTree"

    | command bound to event: "populateTree .fc.tv.tree [.fc.tv.tree focus]"

    | Code is below

    The code you posted works for me (I don't get that error, and from the
    code logic, I could not understand how populateTree could not be
    defined), so there probably is something else wrong. Are you using
    additional namespace code around that example?

    | ttk::treeview $tw.tree -columns {fullpath type size date time} -displaycolumns {size date time} \
    | -yscroll "$tw.vsb set" -xscroll "$tw.hsb set"

    Note that it is always preferable to use [list] to build up callback
    commands:

    ... -yscroll [list $tw.vsb set] -xscroll [list $tw.hsb set]

    In your example it depends on what $tw is set to whether it makes a
    difference, but if more complex arguments are passed in the callbacks,
    the [list] approach is the better one.

    | 2) How do I get a selection from multiple items treeview to be saved in a variable.

    It seems that [pathname selection] returns the currently selected items,
    so just store that in a variable. But since that seems obvious maybe
    that is not your question...

    HTH
    R'

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to Ralf Fassel on Mon Sep 19 04:05:45 2022
    Hi Ralf,

    Thank you for you response.

    Please pardon as I'm very new to TCL.

    Yes there is an additional namespace around this code, and I have tried multiple examples all seem to give me an invalid name error.

    Is there a way to define "populateTree" so that the error is not generated? or should the tree have it's own name space?

    2) How do I get a selection from multiple items treeview to be saved in a variable.
    It seems that [pathname selection] returns the currently selected items,
    so just store that in a variable. But since that seems obvious maybe
    that is not your question...

    I've tried [pathname selection], it doesn't print anything in console


    On Monday, September 19, 2022 at 11:01:32 AM UTC+1, Ralf Fassel wrote:
    * GeorgeB <[email protected]>
    | Hello,

    | Newbie here, and I'm having some difficulties with treeview in TCL.

    | I'm working off a demo example from Active State TCL.

    | 1) I wondered if someone could help, I get the following error but don't know what to do to fix or how to fix.

    | Error is invalid command error ERROR: invalid command name "populateTree"

    | command bound to event: "populateTree .fc.tv.tree [.fc.tv.tree focus]"

    | Code is below
    The code you posted works for me (I don't get that error, and from the
    code logic, I could not understand how populateTree could not be
    defined), so there probably is something else wrong. Are you using
    additional namespace code around that example?
    | ttk::treeview $tw.tree -columns {fullpath type size date time} -displaycolumns {size date time} \
    | -yscroll "$tw.vsb set" -xscroll "$tw.hsb set"
    Note that it is always preferable to use [list] to build up callback commands:

    ... -yscroll [list $tw.vsb set] -xscroll [list $tw.hsb set]

    In your example it depends on what $tw is set to whether it makes a difference, but if more complex arguments are passed in the callbacks,
    the [list] approach is the better one.
    | 2) How do I get a selection from multiple items treeview to be saved in a variable.
    It seems that [pathname selection] returns the currently selected items,
    so just store that in a variable. But since that seems obvious maybe
    that is not your question...

    HTH
    R'

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alan Grunwald@21:1/5 to GeorgeB on Mon Sep 19 12:45:09 2022
    On 18/09/2022 20:28, GeorgeB wrote:
    Hello,

    Newbie here, and I'm having some difficulties with treeview in TCL.

    I'm working off a demo example from Active State TCL.

    1) I wondered if someone could help, I get the following error but don't know what to do to fix or how to fix.

    Error is invalid command error ERROR: invalid command name "populateTree"

    command bound to event: "populateTree .fc.tv.tree [.fc.tv.tree focus]"

    Code is below

    2) How do I get a selection from multiple items treeview to be saved in a variable.


    # temp dir to mimic Network dir
    set ::dir "C:/Dev"

    proc populateRoots {tree} {
    populateTree $tree [$tree insert {} end -text "Network File" \
    -values [list $::dir directory]]
    }

    ## Code to populate a node of the tree
    proc populateTree {tree node} {
    if {[$tree set $node type] ne "directory"} {
    return
    }
    set path [$tree set $node fullpath]
    $tree delete [$tree children $node]
    foreach f [lsort -dictionary [glob -nocomplain -dir $path *]] {
    set type [file type $f]
    set id [$tree insert $node end -text [file tail $f] \
    -values [list $f $type]]
    if {$type eq "directory"} {
    ## Make it so that this node is openable
    $tree insert $id 0 -text dummy ;# a dummy
    $tree item $id -text [file tail $f]/
    } elseif {$type eq "file"} {
    set size [file size $f]
    set ttime [file mtime $f]
    ## Format the file size nicely
    if {$size >= 1024*1024*1024} {
    set size [format %.1f\ GB [expr {$size/1024/1024/1024.}]]
    } elseif {$size >= 1024*1024} {
    set size [format %.1f\ MB [expr {$size/1024/1024.}]]
    } elseif {$size >= 1024} {
    set size [format %.1f\ kB [expr {$size/1024.}]]
    } else {
    append size " bytes"
    }
    $tree set $id size $size
    }
    }

    # Stop this code from rerunning on the current node
    $tree set $node type processedDirectory
    }

    # ## Create the tree and set it up


    ttk::treeview $tw.tree -columns {fullpath type size date time} -displaycolumns {size date time} \
    -yscroll "$tw.vsb set" -xscroll "$tw.hsb set"
    ttk::scrollbar $tw.vsb -orient vertical -command "$tw.tree yview"
    ttk::scrollbar $tw.hsb -orient horizontal -command "$tw.tree xview"
    $tw.tree heading \#0 -text "Directory Structure"
    $tw.tree heading size -text "File Size"
    $tw.tree column size -stretch 0 -width 70
    populateRoots $tw.tree
    bind $tw.tree <<TreeviewOpen>> {populateTree %W [%W focus]}

    # ## Arrange the tree and its scrollbars in the toplevel
    lower [ttk::frame $tw.dummy]
    pack $tw.dummy -fill both -expand 1
    grid $tw.tree $tw.vsb -sticky nsew -in $tw.dummy
    grid $tw.hsb -sticky nsew -in $tw.dummy
    grid columnconfigure $tw.dummy 0 -weight 1
    grid rowconfigure $tw.dummy 0 -weight 1


    Thank you in advance

    George

    The error message says that the system doesn't know anything about the
    command populateTree. This is a little surprising since you have defined
    it in the code you have posted.

    Probably what has happened is that when you executed "proc populateTree
    {tree node} {...}" you were inside a namespace, so you ended up defining <someNamespace>::populateTree; since the code associated with the event operates in the global namespace, it is looking for ::populateTree and
    can't find it.

    You can ensure that you define populateTree in the global namespace by
    changing your [proc] statment to "proc ::populateTree {tree node}...".
    If you are interested to know where your current populateTree command is
    ending up, you could add "puts stdout [namespace current]" immediately
    before the [proc] statement, which willwrite the current namespace to
    standard output when the script is first sourced.

    Good luck sorting out your script, I hope this proves helpful,

    Alan

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to Alan Grunwald on Mon Sep 19 05:28:32 2022
    On Monday, September 19, 2022 at 12:45:29 PM UTC+1, Alan Grunwald wrote:
    On 18/09/2022 20:28, GeorgeB wrote:
    Hello,

    Newbie here, and I'm having some difficulties with treeview in TCL.

    I'm working off a demo example from Active State TCL.

    1) I wondered if someone could help, I get the following error but don't know what to do to fix or how to fix.

    Error is invalid command error ERROR: invalid command name "populateTree"

    command bound to event: "populateTree .fc.tv.tree [.fc.tv.tree focus]"

    Code is below

    2) How do I get a selection from multiple items treeview to be saved in a variable.


    # temp dir to mimic Network dir
    set ::dir "C:/Dev"

    proc populateRoots {tree} {
    populateTree $tree [$tree insert {} end -text "Network File" \
    -values [list $::dir directory]]
    }

    ## Code to populate a node of the tree
    proc populateTree {tree node} {
    if {[$tree set $node type] ne "directory"} {
    return
    }
    set path [$tree set $node fullpath]
    $tree delete [$tree children $node]
    foreach f [lsort -dictionary [glob -nocomplain -dir $path *]] {
    set type [file type $f]
    set id [$tree insert $node end -text [file tail $f] \
    -values [list $f $type]]
    if {$type eq "directory"} {
    ## Make it so that this node is openable
    $tree insert $id 0 -text dummy ;# a dummy
    $tree item $id -text [file tail $f]/
    } elseif {$type eq "file"} {
    set size [file size $f]
    set ttime [file mtime $f]
    ## Format the file size nicely
    if {$size >= 1024*1024*1024} {
    set size [format %.1f\ GB [expr {$size/1024/1024/1024.}]]
    } elseif {$size >= 1024*1024} {
    set size [format %.1f\ MB [expr {$size/1024/1024.}]]
    } elseif {$size >= 1024} {
    set size [format %.1f\ kB [expr {$size/1024.}]]
    } else {
    append size " bytes"
    }
    $tree set $id size $size
    }
    }

    # Stop this code from rerunning on the current node
    $tree set $node type processedDirectory
    }

    # ## Create the tree and set it up


    ttk::treeview $tw.tree -columns {fullpath type size date time} -displaycolumns {size date time} \
    -yscroll "$tw.vsb set" -xscroll "$tw.hsb set"
    ttk::scrollbar $tw.vsb -orient vertical -command "$tw.tree yview" ttk::scrollbar $tw.hsb -orient horizontal -command "$tw.tree xview" $tw.tree heading \#0 -text "Directory Structure"
    $tw.tree heading size -text "File Size"
    $tw.tree column size -stretch 0 -width 70
    populateRoots $tw.tree
    bind $tw.tree <<TreeviewOpen>> {populateTree %W [%W focus]}

    # ## Arrange the tree and its scrollbars in the toplevel
    lower [ttk::frame $tw.dummy]
    pack $tw.dummy -fill both -expand 1
    grid $tw.tree $tw.vsb -sticky nsew -in $tw.dummy
    grid $tw.hsb -sticky nsew -in $tw.dummy
    grid columnconfigure $tw.dummy 0 -weight 1
    grid rowconfigure $tw.dummy 0 -weight 1


    Thank you in advance

    George
    The error message says that the system doesn't know anything about the command populateTree. This is a little surprising since you have defined
    it in the code you have posted.

    Probably what has happened is that when you executed "proc populateTree
    {tree node} {...}" you were inside a namespace, so you ended up defining <someNamespace>::populateTree; since the code associated with the event operates in the global namespace, it is looking for ::populateTree and
    can't find it.

    You can ensure that you define populateTree in the global namespace by changing your [proc] statment to "proc ::populateTree {tree node}...".
    If you are interested to know where your current populateTree command is ending up, you could add "puts stdout [namespace current]" immediately
    before the [proc] statement, which willwrite the current namespace to standard output when the script is first sourced.

    Good luck sorting out your script, I hope this proves helpful,

    Alan


    Alan, you genius....you have sorted the problem, thank you so much.
    It also sorted one other issue I was having populating the nodes from a folder in network location...Thank you, I was going round in circles!.

    Now I just need to figure out how to print selection (single or multiple) into console. It always comes up blank...

    If you any tips or suggestion I'd greatly appreciate.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ralf Fassel@21:1/5 to All on Mon Sep 19 14:40:43 2022
    * GeorgeB <[email protected]>
    | Hi Ralf,

    | Thank you for you response.

    | Please pardon as I'm very new to TCL.

    | Yes there is an additional namespace around this code, and I have
    | tried multiple examples all seem to give me an invalid name error.

    Usually it is best to post a _complete_ example which actually shows the
    error. The code you posted did not use an additional namespace, so it
    does not show the error.

    If you define a proc inside a namespace, you need to specify that
    namespace in callbacks, since those callbacks usually are invoked
    outside of that namespace when they run later.

    Instead of
    bind $tw.tree <<TreeviewOpen>> {populateTree %W [%W focus]}
    try
    bind $tw.tree <<TreeviewOpen>> [namespace code [list populateTree %W [%W focus]]

    The [namespace code ...] captures the current namespace for the
    asynchronous invocation of the command later.

    | Is there a way to define "populateTree" so that the error is not
    | generated? or should the tree have it's own name space?

    It's not how "populateTree" is defined, but how it is to be called.
    If you define it inside a namespace, you need to specify that namespace
    when calling it.

    Note that procs which are defined in the same namespace can call other
    procs in that namespace without specifying that namespace explicitly,
    but for callbacks like [bind] you need to specfiy the namespace via
    [namespace code ...].

    | 2) How do I get a selection from multiple items treeview to be saved in a variable.
    | > It seems that [pathname selection] returns the currently selected items,
    | > so just store that in a variable. But since that seems obvious maybe
    | > that is not your question...

    | I've tried [pathname selection], it doesn't print anything in console

    You need to replace 'pathname' by $tw.tree, then select something in the treeview, then issue that command:

    set selected [$tw.tree selection]
    puts $selected
    => I004 I005 I006

    HTH
    R'

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to GeorgeB on Mon Sep 19 13:49:34 2022
    GeorgeB <[email protected]> wrote:
    On Monday, September 19, 2022 at 12:45:29 PM UTC+1, Alan Grunwald wrote:
    On 18/09/2022 20:28, GeorgeB wrote:
    Error is invalid command error ERROR: invalid command name "populateTree" >> >

    Probably what has happened is that when you executed "proc populateTree
    {tree node} {...}" you were inside a namespace, so you ended up defining
    <someNamespace>::populateTree; since the code associated with the event
    operates in the global namespace, it is looking for ::populateTree and
    can't find it.

    You can ensure that you define populateTree in the global namespace by
    changing your [proc] statment to "proc ::populateTree {tree node}...".
    If you are interested to know where your current populateTree command is
    ending up, you could add "puts stdout [namespace current]" immediately
    before the [proc] statement, which willwrite the current namespace to
    standard output when the script is first sourced.

    Alan, you genius....you have sorted the problem, thank you so much.

    If you any tips or suggestion I'd greatly appreciate.

    If you do wish to use namespaces to structure your code, and if you do
    not wish to pollute the global namespace (implied yes given you appear
    to be using namespaces), then you should use Ralf's suggestion of
    utilizing 'namespace code' to generate the callback script bound to the
    binding event.

    That will do the work of setting up the binding to call the proc inside
    the namespace where it is defined, without you having to add lots of
    global procs or having to manually handle the insertion of the
    namespace pathname for each binding.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ralf Fassel@21:1/5 to All on Mon Sep 19 17:27:53 2022
    * Ralf Fassel <[email protected]>
    | Instead of
    | bind $tw.tree <<TreeviewOpen>> {populateTree %W [%W focus]}
    | try
    | bind $tw.tree <<TreeviewOpen>> [namespace code [list populateTree %W [%W focus]]

    Nah, that's nonsense, since the [%W focus] needs to run later when the
    binding is triggered, not when it is defined.

    Easiest solution seems to move the "%W focus" into populateTree:

    proc populateTree {tree node} {
    ...
    =>
    proc populateTree {tree {node ""}} {
    if {$node eq ""} {
    set node [$tree focus]
    }
    ...

    and then just do

    bind $tw.tree <<TreeviewOpen>> [namespace code [list populateTree %W]]

    HTH
    R'

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to Ralf Fassel on Mon Sep 19 08:32:43 2022
    On Monday, September 19, 2022 at 1:40:47 PM UTC+1, Ralf Fassel wrote:
    * GeorgeB <[email protected]>
    | Hi Ralf,

    | Thank you for you response.

    | Please pardon as I'm very new to TCL.

    | Yes there is an additional namespace around this code, and I have
    | tried multiple examples all seem to give me an invalid name error.
    Usually it is best to post a _complete_ example which actually shows the error. The code you posted did not use an additional namespace, so it
    does not show the error.

    If you define a proc inside a namespace, you need to specify that
    namespace in callbacks, since those callbacks usually are invoked
    outside of that namespace when they run later.

    Instead of
    bind $tw.tree <<TreeviewOpen>> {populateTree %W [%W focus]}
    try
    bind $tw.tree <<TreeviewOpen>> [namespace code [list populateTree %W [%W focus]]

    The [namespace code ...] captures the current namespace for the
    asynchronous invocation of the command later.
    | Is there a way to define "populateTree" so that the error is not
    | generated? or should the tree have it's own name space?
    It's not how "populateTree" is defined, but how it is to be called.
    If you define it inside a namespace, you need to specify that namespace
    when calling it.

    Note that procs which are defined in the same namespace can call other
    procs in that namespace without specifying that namespace explicitly,
    but for callbacks like [bind] you need to specfiy the namespace via [namespace code ...].
    | 2) How do I get a selection from multiple items treeview to be saved in a variable.
    | > It seems that [pathname selection] returns the currently selected items, | > so just store that in a variable. But since that seems obvious maybe
    | > that is not your question...

    | I've tried [pathname selection], it doesn't print anything in console
    You need to replace 'pathname' by $tw.tree, then select something in the treeview, then issue that command:

    set selected [$tw.tree selection]
    puts $selected
    I004 I005 I006

    HTH
    R'


    Hi Rich and Ralf,

    Thank you for the suggestion,

    I've replaced the binding with
    bind $tw.tv.tree <<TreeviewOpen>> {::FG::populateTree %W [%W focus]}

    However if I use bind $tw.tree <<TreeviewOpen>> [namespace code [list populateTree %W [%W focus]]], where code = container name I get error
    ERROR: invalid command name "%W"
    in "%W focus"


    | I've tried [pathname selection], it doesn't print anything in console
    You need to replace 'pathname' by $tw.tree, then select something in the treeview, then issue that command:

    set selected [$tw.tree selection]
    puts $selected
    I004 I005 I006

    I'd done exactly as you had suggested...but realised I forgot to select items in the tree....doh!!!

    I'm assuming I will have to map the id e.g. I004 etc to actual value in the tree?
    i.e. if id = I004 and I004 relates to file config.txt in tree then I'll have to map it somehow to each other .

    Is it possible to selected a node and get all values underneath it? On selection of the node is just gives me one single ID?
    e.g.
    Network file
    |- Folder 1
    |- file0.txt
    |- file1.txt
    |- file2.txt
    |- file3.txt

    I would like to get all items underneath Folder 1 by selecting Folder 1

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to Ralf Fassel on Mon Sep 19 08:39:45 2022
    On Monday, September 19, 2022 at 4:27:58 PM UTC+1, Ralf Fassel wrote:
    * Ralf Fassel <[email protected]>
    | Instead of
    | bind $tw.tree <<TreeviewOpen>> {populateTree %W [%W focus]}
    | try
    | bind $tw.tree <<TreeviewOpen>> [namespace code [list populateTree %W [%W focus]]
    Nah, that's nonsense, since the [%W focus] needs to run later when the binding is triggered, not when it is defined.

    Easiest solution seems to move the "%W focus" into populateTree:
    proc populateTree {tree node} {
    ...

    proc populateTree {tree {node ""}} {
    if {$node eq ""} {
    set node [$tree focus]
    }
    ...

    and then just do

    bind $tw.tree <<TreeviewOpen>> [namespace code [list populateTree %W]]

    HTH
    R'

    Ralf
    I just saw this as I posted my last reply 5mins ago...this seems to work better.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to GeorgeB on Mon Sep 19 21:03:24 2022
    GeorgeB <[email protected]> wrote:
    However if I use bind $tw.tree <<TreeviewOpen>> [namespace code [list populateTree %W [%W focus]]]
    , where code = container name I get error
    ERROR: invalid command name "%W"
    in "%W focus"

    That is because if you look at the above, you are asking tcl to execute
    a command named %W (note the []') at the time you define the binding.

    There is no command named %W defined (unless you defined a proc by that
    name), so you get "invalid command name "%W".

    You would be best to follow Ralf's suggestion and perform the 'focus'
    inside the proc, and just pass the window name that Tk inserts for %W
    when the binding fires into the proc, then use that window name to
    perform the focus. Note, are you sure you want to do a focus here?

    | I've tried [pathname selection], it doesn't print anything in
    console You need to replace 'pathname' by $tw.tree, then select
    something in the treeview, then issue that command:

    set selected [$tw.tree selection]
    puts $selected
    I004 I005 I006

    I'd done exactly as you had suggested...but realised I forgot to
    select items in the tree....doh!!!

    I'm assuming I will have to map the id e.g. I004 etc to actual value
    in the tree? i.e. if id = I004 and I004 relates to file config.txt
    in tree then I'll have to map it somehow to each other .

    You get the internal ID's of the selected items. That is all Tk knows.
    If you need to relate those ID's to something else then you have to
    build that relationship map yourself.

    Is it possible to selected a node and get all values underneath it?
    On selection of the node is just gives me one single ID?

    You can get a list of the children of a given node with the 'children' subcommand (see the treeview man page).

    If you wish to recurse down the tree, then you have to write your own
    proc to walk down the tree and get all the grand/greatgrand/etc.
    children.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From saitology9@21:1/5 to Rich on Mon Sep 19 18:39:24 2022
    On 9/19/22 5:03 PM, Rich wrote:
    GeorgeB <[email protected]> wrote:
    However if I use bind $tw.tree <<TreeviewOpen>> [namespace code [list populateTree %W [%W focus]]]
    , where code = container name I get error
    ERROR: invalid command name "%W"
    in "%W focus"

    That is because if you look at the above, you are asking tcl to execute
    a command named %W (note the []') at the time you define the binding.

    There is no command named %W defined (unless you defined a proc by that name), so you get "invalid command name "%W".

    You would be best to follow Ralf's suggestion and perform the 'focus'

    I agree Ralf's suggestion is the best approach here. Nevertheless, it
    might be useful to OP to know that they could fix the error above by
    properly constructing the callback like so:


    bind $tw.tree <<TreeviewOpen>> \
    [namespace code [list populateTree %W [list %W focus]]]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et4@21:1/5 to GeorgeB on Mon Sep 19 19:56:07 2022
    On 9/19/2022 5:28 AM, GeorgeB wrote:



    Now I just need to figure out how to print selection (single or multiple) into console. It always comes up blank...

    If you any tips or suggestion I'd greatly appreciate.


    Welcome new tcl programmer.

    Might I suggest "The Tcl Programming Language" book, both paper and pdf.

    https://www.magicsplat.com/ttpl/index.html

    I recommend both. They are an exact match; searching in the pdf can take you to the exact same page in the book.

    The index and TOC in the pdf are hyperlinked. You can download the TOC for free on the above page and you can get a zip from there with all the utility functions used in the book as well.

    You mentioned you print to the console, so probably on windows. Snippets of code from the book can be copied/pasted from the pdf right into a console window where you can interactively try things out.

    Your issue with callbacks vs. scripts is discussed in section 10.7.1. and 12.2.1 when combined with namespaces.

    I also recommend the free and portable PDF Xchange Viewer program on windows.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et4@21:1/5 to All on Mon Sep 19 20:13:01 2022
    Almost forgot, a great on-line manual too:

    https://www.magicsplat.com/tcl-docs/docindex.html

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to All on Tue Sep 20 00:25:34 2022
    On Tuesday, September 20, 2022 at 4:13:05 AM UTC+1, et4 wrote:
    Almost forgot, a great on-line manual too:

    https://www.magicsplat.com/tcl-docs/docindex.html

    Morning Rich, saitology9 & et4,

    I've got most of the errors sorted (Ralf/Rich, thank you for the help, most appreciated).

    I think as I get use to TCL I'll have a better understanding, right now I've been thrown in the deep end and hence steep learning curve.

    @Rich thank you for the clarification on the mapping, I suspected as such but thought I'd double check.

    @et4, thank you for the resource, anything on tree view (for immediate help), plus I need to add more widgets to treeview once I've figured out mapping.

    Lastly, if I have more questions relating to the code shown in my first thread (as I build on it), should I create a new thread or continue with current thread for continuity?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ralf Fassel@21:1/5 to All on Tue Sep 20 10:37:16 2022
    * GeorgeB <[email protected]>
    | > set selected [$tw.tree selection]
    | > puts $selected
    | > => I004 I005 I006

    | I'd done exactly as you had suggested...but realised I forgot to select items in the tree....doh!!!

    :-)

    | I'm assuming I will have to map the id e.g. I004 etc to actual value in the tree?
    | i.e. if id = I004 and I004 relates to file config.txt in tree then
    | I'll have to map it somehow to each other .

    That would be

    $tw.tree item $item -text

    or any other item option you are interested in:

    foreach s [$tw.tree selection] {
    puts "$s => [$tw.tree item $s -text]"
    }
    =>
    I004 => _csp
    I005 => _rpm
    I006 => _s
    I007 => _sk

    | Is it possible to selected a node and get all values underneath it? On
    | selection of the node is just gives me one single ID? e.g. Network
    | file
    | |- Folder 1
    | |- file0.txt
    | |- file1.txt
    | |- file2.txt
    | |- file3.txt

    | I would like to get all items underneath Folder 1 by selecting Folder 1

    Iterate over

    $tw.tree children $item

    HTH
    R'

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ralf Fassel@21:1/5 to All on Tue Sep 20 10:29:05 2022
    * saitology9 <[email protected]>
    | I agree Ralf's suggestion is the best approach here. Nevertheless, it
    | might be useful to OP to know that they could fix the error above by
    | properly constructing the callback like so:


    | bind $tw.tree <<TreeviewOpen>> \
    | [namespace code [list populateTree %W [list %W focus]]]

    I don't think so, since that just builds a list, but does not *execute*
    the "%W focus" when the binding is triggered. It just passes the string "$tw.tree focus" as second parameter to [populateTree].

    It is usually very tricky to create callbacks with execution syntax in
    them, especially when there might be whitespace involved in the
    parameters (let alone arbitrary user input). The better approach is to
    keep the arguments minimal and put the workload *inside* the callback.

    R'

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to Ralf Fassel on Tue Sep 20 03:57:34 2022
    On Tuesday, September 20, 2022 at 9:37:21 AM UTC+1, Ralf Fassel wrote:
    * GeorgeB <[email protected]>
    | > set selected [$tw.tree selection]
    | > puts $selected
    | > => I004 I005 I006

    | I'd done exactly as you had suggested...but realised I forgot to select items in the tree....doh!!!
    :-)
    | I'm assuming I will have to map the id e.g. I004 etc to actual value in the tree?
    | i.e. if id = I004 and I004 relates to file config.txt in tree then
    | I'll have to map it somehow to each other .
    That would be

    $tw.tree item $item -text

    or any other item option you are interested in:

    foreach s [$tw.tree selection] {
    puts "$s => [$tw.tree item $s -text]"
    }

    I004 => _csp
    I005 => _rpm
    I006 => _s
    I007 => _sk
    | Is it possible to selected a node and get all values underneath it? On
    | selection of the node is just gives me one single ID? e.g. Network
    | file
    | |- Folder 1
    | |- file0.txt
    | |- file1.txt
    | |- file2.txt
    | |- file3.txt

    | I would like to get all items underneath Folder 1 by selecting Folder 1 Iterate over

    $tw.tree children $item

    HTH
    R'

    :)

    Thanks Ralf.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to GeorgeB on Tue Sep 20 13:50:01 2022
    GeorgeB <[email protected]> wrote:
    On Tuesday, September 20, 2022 at 9:37:21 AM UTC+1, Ralf Fassel wrote:
    * GeorgeB <[email protected]>
    | > set selected [$tw.tree selection]
    | > puts $selected
    | > => I004 I005 I006

    | I'd done exactly as you had suggested...but realised I forgot to
    | select items in the tree....doh!!!
    | :-)
    | I'm assuming I will have to map the id e.g. I004 etc to actual value in the tree?
    | i.e. if id = I004 and I004 relates to file config.txt in tree then
    | I'll have to map it somehow to each other .
    That would be

    $tw.tree item $item -text

    or any other item option you are interested in:

    foreach s [$tw.tree selection] {
    puts "$s => [$tw.tree item $s -text]"
    }

    :)

    Thanks Ralf.

    Note also that you can add a list of tags to treeview items (read the
    manpage for details). You can make use of tags for, among other uses,
    tracking how a given row relates to the other data you are marshalling.

    Note that the tags associated with an item are a Tcl list, so use
    list operators to manipulate them.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to Rich on Tue Sep 20 08:30:44 2022
    On Tuesday, September 20, 2022 at 2:50:06 PM UTC+1, Rich wrote:
    GeorgeB <[email protected]> wrote:
    On Tuesday, September 20, 2022 at 9:37:21 AM UTC+1, Ralf Fassel wrote:
    * GeorgeB <[email protected]>
    | > set selected [$tw.tree selection]
    | > puts $selected
    | > => I004 I005 I006

    | I'd done exactly as you had suggested...but realised I forgot to
    | select items in the tree....doh!!!
    | :-)
    | I'm assuming I will have to map the id e.g. I004 etc to actual value in the tree?
    | i.e. if id = I004 and I004 relates to file config.txt in tree then
    | I'll have to map it somehow to each other .
    That would be

    $tw.tree item $item -text

    or any other item option you are interested in:

    foreach s [$tw.tree selection] {
    puts "$s => [$tw.tree item $s -text]"
    }

    :)

    Thanks Ralf.

    Note also that you can add a list of tags to treeview items (read the
    manpage for details). You can make use of tags for, among other uses, tracking how a given row relates to the other data you are marshalling.

    Note that the tags associated with an item are a Tcl list, so use
    list operators to manipulate them.

    Thanks Rich,

    One thing I'm trying to figure out is how to filter on file extension.

    Now I'm passing two folder (Folder 1 & Folder 2) to simulate the structure (see below), the tree structure is created as one would expect. However I was hoping to filter on *.ini files.

    In doing so I was trying to figure out were it determines the file names before it populates the tree.

    For Folder with out sub folder e.g. Folder 2, applying filter to "foreach f [lsort -dictionary [glob -nocomplain -dir $path *.ini]]" works, but not for folder with sub folder i.e. Folder 1

    |- Folder 1
    |- Sub folder
    |- file0.ini
    |- file1.docx
    |- Sub Folder 2
    |- file1.txt
    |- file1.ini
    |- Sub Folder 3
    |- file2.ini
    |- file2.txt
    |- file2.docx

    |- Folder 2
    |- file01.ini
    |- file11.docx
    |- file21.xlsx
    |- file31.txt

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to GeorgeB on Tue Sep 20 17:22:37 2022
    GeorgeB <[email protected]> wrote:
    On Tuesday, September 20, 2022 at 2:50:06 PM UTC+1, Rich wrote:
    Note also that you can add a list of tags to treeview items (read
    the manpage for details). You can make use of tags for, among other
    uses, tracking how a given row relates to the other data you are
    marshalling.

    Note that the tags associated with an item are a Tcl list, so use
    list operators to manipulate them.

    Thanks Rich,

    One thing I'm trying to figure out is how to filter on file
    extension.

    Read the 'file' manpage, specifically the "extension" subcommand.

    Now I'm passing two folder (Folder 1 & Folder 2) to simulate the
    structure (see below), the tree structure is created as one would
    expect. However I was hoping to filter on *.ini files.

    In doing so I was trying to figure out were it determines the file
    names before it populates the tree.

    As we have no idea what "it" is, we are at a loss to offer much in the
    way of suggestions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From saitology9@21:1/5 to GeorgeB on Tue Sep 20 13:30:22 2022
    On 9/20/22 11:30 AM, GeorgeB wrote:

    For Folder with out sub folder e.g. Folder 2, applying filter to "foreach f [lsort -dictionary [glob -nocomplain -dir $path *.ini]]" works, but not for folder with sub folder i.e. Folder 1

    |- Folder 1
    |- Sub folder
    |- file0.ini
    |- file1.docx

    Hello,

    I doubt that, as Rich pointed out, "it" knows that you mean to separate
    files from folders. Here you are dealing with two kinds of nodes in the
    tree widget, and I believe it is up to you to determine when to add a
    "folder" node and when to add a ".ini" file, or something else, and
    where to add them in the tree hierarchy.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From saitology9@21:1/5 to Ralf Fassel on Tue Sep 20 13:23:05 2022
    On 9/20/22 4:29 AM, Ralf Fassel wrote:

    | bind $tw.tree <<TreeviewOpen>> \
    | [namespace code [list populateTree %W [list %W focus]]]

    I don't think so, since that just builds a list, but does not *execute*
    the "%W focus" when the binding is triggered. It just passes the string "$tw.tree focus" as second parameter to [populateTree].


    True indeed - it does not execute any code. What it does is enable
    proper substitution as the original author of that code must have
    intended, and passes its result as the argument. The argument happens
    to contain a valid command that can be eval'ed, e.g., in the callback proc.

    I am still learning the language but my suspicion is that anyone using
    "%W" would know that it is only there to be substituted with the actual
    target window name later when the callback takes place. Given the fact
    that the original code the OP posted was from a demo file from
    ActiveState, I assumed that they would know what they were doing with
    that type of callback argument construction.


    I completely agree with the rest of your post.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From saitology9@21:1/5 to GeorgeB on Tue Sep 20 15:11:23 2022
    On 9/20/22 2:34 PM, GeorgeB wrote:

    Hence I was trying to ascertain where within the code (as posted in the first thread), does it create a node for Folder 1 > Sub Folder > file

    Since I couldn't figure it out I came asking help.


    I took a look at the initial code you posted.

    The first node, i.e., the root, is created when the widget is created by populateRoots. This proc creates a folder node associated with "C:/Dev".

    Then according to the binding, whenever you click on a node,
    populateTree is called. This one does a glob to find the files and
    folders, and creates a node *at that level*, i.e., inside the node that
    was clicked.

    I am not fully sure what you are trying to achieve with ".ini" files but
    the proper place to trim it might be in an if-statement inside the
    foeach loop right there. Put an extra check for file extension inside
    the block:

    ..
    } elseif {$type eq "file"} {
    ..

    and handle it as you wish.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to All on Tue Sep 20 11:35:48 2022
    On Tuesday, September 20, 2022 at 6:30:31 PM UTC+1, saitology9 wrote:
    On 9/20/22 11:30 AM, GeorgeB wrote:

    For Folder with out sub folder e.g. Folder 2, applying filter to "foreach f [lsort -dictionary [glob -nocomplain -dir $path *.ini]]" works, but not for folder with sub folder i.e. Folder 1

    |- Folder 1
    |- Sub folder
    |- file0.ini
    |- file1.docx
    Hello,

    I doubt that, as Rich pointed out, "it" knows that you mean to separate
    files from folders. Here you are dealing with two kinds of nodes in the
    tree widget, and I believe it is up to you to determine when to add a "folder" node and when to add a ".ini" file, or something else, and
    where to add them in the tree hierarchy.

    Thanks saitology9, I'll have a think tomorrow.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to Rich on Tue Sep 20 11:34:36 2022
    On Tuesday, September 20, 2022 at 6:22:42 PM UTC+1, Rich wrote:
    GeorgeB <[email protected]> wrote:
    On Tuesday, September 20, 2022 at 2:50:06 PM UTC+1, Rich wrote:
    Note also that you can add a list of tags to treeview items (read
    the manpage for details). You can make use of tags for, among other
    uses, tracking how a given row relates to the other data you are
    marshalling.

    Note that the tags associated with an item are a Tcl list, so use
    list operators to manipulate them.

    Thanks Rich,

    One thing I'm trying to figure out is how to filter on file
    extension.
    Read the 'file' manpage, specifically the "extension" subcommand.
    Now I'm passing two folder (Folder 1 & Folder 2) to simulate the
    structure (see below), the tree structure is created as one would
    expect. However I was hoping to filter on *.ini files.

    In doing so I was trying to figure out were it determines the file
    names before it populates the tree.
    As we have no idea what "it" is, we are at a loss to offer much in the
    way of suggestions.

    Yes I've read that bit of the documentation and can filter within directories with extensions.

    What I meant was in the code I posted in my first thread, I can't seem to figure out where to correctly apply the filter.

    If I apply it where I think I should, foreach f [lsort -dictionary [glob -nocomplain -dir $path *.ini]], doesn't yield the desired result. This only seems to work with folders where files are at top level e.g. Folder 2 in my previous thread.

    Hence I was trying to ascertain where within the code (as posted in the first thread), does it create a node for Folder 1 > Sub Folder > file

    Since I couldn't figure it out I came asking help.

    Maybe this is the downside of using demo.

    Anyhoo, I'll try with fresh eyes approach tomorrow.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to All on Tue Sep 20 12:32:34 2022
    On Tuesday, September 20, 2022 at 8:11:34 PM UTC+1, saitology9 wrote:
    On 9/20/22 2:34 PM, GeorgeB wrote:

    Hence I was trying to ascertain where within the code (as posted in the first thread), does it create a node for Folder 1 > Sub Folder > file

    Since I couldn't figure it out I came asking help.

    I took a look at the initial code you posted.

    The first node, i.e., the root, is created when the widget is created by populateRoots. This proc creates a folder node associated with "C:/Dev".

    Then according to the binding, whenever you click on a node,
    populateTree is called. This one does a glob to find the files and
    folders, and creates a node *at that level*, i.e., inside the node that
    was clicked.

    I am not fully sure what you are trying to achieve with ".ini" files but
    the proper place to trim it might be in an if-statement inside the
    foeach loop right there. Put an extra check for file extension inside
    the block:

    ..
    } elseif {$type eq "file"} {
    ..

    and handle it as you wish.

    Hi saitology9,

    Thank you for your response, I "kind of "worked that out in last half hour and did something very similar to what you described.

    I'll give it a bit more thought tomorrow.

    The goal is to populate the tree with specific file type , in this case any files with .ini extension and ignore the rest.

    Lastly can't thank you folks (Ralf, Rich and yourself) enough, every exchange helps me...trust me.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 21 14:18:01 2022
    The goal is to populate the tree with specific file type , in this case any files with .ini extension and ignore the rest.

    You might look at the fileutil package from tcllib, in particular find or findByPattern
    Something like:

    package require fileutil

    set iniFiles [fileutil::findByPattern C:/Dev -glob {*.ini}]

    would give you a list of complete paths to all .ini files in and under the C:/Dev directory. Directory tree branches with no ini files woud not be in the list. I'm not sure if that is an advantage in your case or not.


    Dave B

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to All on Wed Sep 21 13:35:45 2022
    On Tuesday, September 20, 2022 at 8:11:34 PM UTC+1, saitology9 wrote:
    On 9/20/22 2:34 PM, GeorgeB wrote:

    Hence I was trying to ascertain where within the code (as posted in the first thread), does it create a node for Folder 1 > Sub Folder > file

    Since I couldn't figure it out I came asking help.

    I took a look at the initial code you posted.

    The first node, i.e., the root, is created when the widget is created by populateRoots. This proc creates a folder node associated with "C:/Dev".

    Then according to the binding, whenever you click on a node,
    populateTree is called. This one does a glob to find the files and
    folders, and creates a node *at that level*, i.e., inside the node that
    was clicked.

    I am not fully sure what you are trying to achieve with ".ini" files but
    the proper place to trim it might be in an if-statement inside the
    foeach loop right there. Put an extra check for file extension inside
    the block:

    ..
    } elseif {$type eq "file"} {
    ..

    and handle it as you wish.

    I was trying to re-write the code so that I could filter on a specific file type. I got 90% sorted :) but seem to have messed something else....

    Now I can't seem to get the "Size Date Time" columns to populate correctly, basically Time populates under Size and Date and Time are empty.

    I've re-created code here:

    ##########################
    package require Tk

    set tw .tree
    catch {destroy $tw}
    toplevel $tw
    wm title $tw "Directory Browser"
    wm iconname $tw "tree"
    positionWindow $tw


    set file_list {A B C D E}
    ttk::treeview $tw.tree -columns {fullpath type size date time} -displaycolumns {size date time} -yscroll [list $tw.vsb set] -xscroll [list $tw.hsb set]
    ttk::scrollbar $tw.vsb -orient vertical -command "$tw.tree yview" ttk::scrollbar $tw.hsb -orient horizontal -command "$tw.tree xview"
    $tw.tree heading \#0 -text "Directory"
    $tw.tree column #0 -anchor e -minwidth 150 -width 250 -stretch 1
    $tw.tree heading size -text "Size"
    $tw.tree column size -stretch 0 -width 70
    $tw.tree heading time -text "Time"
    $tw.tree column time -stretch 0 -width 70
    $tw.tree heading date -text "Date"
    $tw.tree column date -stretch 0 -width 70


    $tw.tree insert {} end -id Folder -text "Folder 1"
    foreach key [lsort $file_list] {
    $tw.tree insert Folder end -text $key -values [list 80KB 18:00 21/09/2022]
    }

    lower [ttk::frame $tw.dummy]
    pack $tw.dummy -fill both -expand 1
    grid $tw.tree $tw.vsb -sticky nsew -in $tw.dummy
    grid $tw.hsb -sticky nsew -in $tw.dummy
    grid columnconfigure $tw.dummy 0 -weight 1
    grid rowconfigure $tw.dummy 0 -weight 1
    grid columnconfigure $tw 2 -weight 1
    grid rowconfigure $tw 2 -weight 1

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to GeorgeB on Wed Sep 21 13:42:56 2022
    On Wednesday, September 21, 2022 at 9:35:48 PM UTC+1, GeorgeB wrote:
    On Tuesday, September 20, 2022 at 8:11:34 PM UTC+1, saitology9 wrote:
    On 9/20/22 2:34 PM, GeorgeB wrote:

    Hence I was trying to ascertain where within the code (as posted in the first thread), does it create a node for Folder 1 > Sub Folder > file

    Since I couldn't figure it out I came asking help.

    I took a look at the initial code you posted.

    The first node, i.e., the root, is created when the widget is created by populateRoots. This proc creates a folder node associated with "C:/Dev".

    Then according to the binding, whenever you click on a node,
    populateTree is called. This one does a glob to find the files and
    folders, and creates a node *at that level*, i.e., inside the node that
    was clicked.

    I am not fully sure what you are trying to achieve with ".ini" files but the proper place to trim it might be in an if-statement inside the
    foeach loop right there. Put an extra check for file extension inside
    the block:

    ..
    } elseif {$type eq "file"} {
    ..

    and handle it as you wish.
    I was trying to re-write the code so that I could filter on a specific file type. I got 90% sorted :) but seem to have messed something else....

    Now I can't seem to get the "Size Date Time" columns to populate correctly, basically Time populates under Size and Date and Time are empty.

    I've re-created code here:

    ##########################
    package require Tk

    set tw .tree
    catch {destroy $tw}
    toplevel $tw
    wm title $tw "Directory Browser"
    wm iconname $tw "tree"
    positionWindow $tw


    set file_list {A B C D E}
    ttk::treeview $tw.tree -columns {fullpath type size date time} -displaycolumns {size date time} -yscroll [list $tw.vsb set] -xscroll [list $tw.hsb set]
    ttk::scrollbar $tw.vsb -orient vertical -command "$tw.tree yview" ttk::scrollbar $tw.hsb -orient horizontal -command "$tw.tree xview"
    $tw.tree heading \#0 -text "Directory"
    $tw.tree column #0 -anchor e -minwidth 150 -width 250 -stretch 1
    $tw.tree heading size -text "Size"
    $tw.tree column size -stretch 0 -width 70
    $tw.tree heading time -text "Time"
    $tw.tree column time -stretch 0 -width 70
    $tw.tree heading date -text "Date"
    $tw.tree column date -stretch 0 -width 70


    $tw.tree insert {} end -id Folder -text "Folder 1"
    foreach key [lsort $file_list] {
    $tw.tree insert Folder end -text $key -values [list 80KB 18:00 21/09/2022]
    }

    lower [ttk::frame $tw.dummy]
    pack $tw.dummy -fill both -expand 1
    grid $tw.tree $tw.vsb -sticky nsew -in $tw.dummy
    grid $tw.hsb -sticky nsew -in $tw.dummy
    grid columnconfigure $tw.dummy 0 -weight 1
    grid rowconfigure $tw.dummy 0 -weight 1
    grid columnconfigure $tw 2 -weight 1
    grid rowconfigure $tw 2 -weight 1

    The line below is created by reading some files from Folder_A but here represented by a variable
    set file_list {A B C D E}

    List below is processed by reading files from Folder_A but here shown as a list of expected values.
    $tw.tree insert Folder end -text $key -values [list 80KB 18:00 21/09/2022]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to [email protected] on Wed Sep 21 13:29:39 2022
    On Wednesday, September 21, 2022 at 3:18:13 PM UTC+1, [email protected] wrote:
    The goal is to populate the tree with specific file type , in this case any files with .ini extension and ignore the rest.
    You might look at the fileutil package from tcllib, in particular find or findByPattern
    Something like:

    package require fileutil

    set iniFiles [fileutil::findByPattern C:/Dev -glob {*.ini}]

    would give you a list of complete paths to all .ini files in and under the C:/Dev directory. Directory tree branches with no ini files woud not be in the list. I'm not sure if that is an advantage in your case or not.


    Dave B

    Hi Dave, thanks I'll have a look at the fileutil function.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From saitology9@21:1/5 to GeorgeB on Wed Sep 21 17:48:09 2022
    On 9/21/22 4:35 PM, GeorgeB wrote:

    I was trying to re-write the code so that I could filter on a specific file type. I got 90% sorted :) but seem to have messed something else....

    Now I can't seem to get the "Size Date Time" columns to populate correctly, basically Time populates under Size and Date and Time are empty.


    Glad to hear you got it sorted.
    I don't recall ever using the ttk::treeview widget but it looks like the
    shift in columns you see is because you are creating the tree widget
    with 5 columns but when you insert nodes into it, you provide data for
    only three columns.


    ttk::treeview $tw.tree -columns {fullpath type size date time} ...

    $tw.tree insert Folder end -text $key -values [list 80KB 18:00 21/09/2022]


    I don't know what your file list looks like (i.e., plain file names,
    full paths, a dictionary, etc.). But you can at least pass the file
    name and its type (may be ".ini"?) as the first two elements of the list:

    % $tw.tree insert Folder end -text $key -values [list $key ".ini" 80KB
    18:00 21/09/2022]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to All on Thu Sep 22 00:28:23 2022
    On Wednesday, September 21, 2022 at 10:48:22 PM UTC+1, saitology9 wrote:
    On 9/21/22 4:35 PM, GeorgeB wrote:

    I was trying to re-write the code so that I could filter on a specific file type. I got 90% sorted :) but seem to have messed something else....

    Now I can't seem to get the "Size Date Time" columns to populate correctly, basically Time populates under Size and Date and Time are empty.

    Glad to hear you got it sorted.
    I don't recall ever using the ttk::treeview widget but it looks like the shift in columns you see is because you are creating the tree widget
    with 5 columns but when you insert nodes into it, you provide data for
    only three columns.


    ttk::treeview $tw.tree -columns {fullpath type size date time} ...
    $tw.tree insert Folder end -text $key -values [list 80KB 18:00 21/09/2022]
    I don't know what your file list looks like (i.e., plain file names,
    full paths, a dictionary, etc.). But you can at least pass the file
    name and its type (may be ".ini"?) as the first two elements of the list:

    % $tw.tree insert Folder end -text $key -values [list $key ".ini" 80KB
    18:00 21/09/2022]

    Yup (and Doh!), you are absolutely correct, I was passing only three elements.... for 5 columns. Apologies for overlooking the that bit...I shouldn't be working so late...

    Thank you saitology9

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to GeorgeB on Thu Sep 22 11:35:01 2022
    On Thursday, September 22, 2022 at 8:28:26 AM UTC+1, GeorgeB wrote:
    On Wednesday, September 21, 2022 at 10:48:22 PM UTC+1, saitology9 wrote:
    On 9/21/22 4:35 PM, GeorgeB wrote:

    I was trying to re-write the code so that I could filter on a specific file type. I got 90% sorted :) but seem to have messed something else....

    Now I can't seem to get the "Size Date Time" columns to populate correctly, basically Time populates under Size and Date and Time are empty.

    Glad to hear you got it sorted.
    I don't recall ever using the ttk::treeview widget but it looks like the shift in columns you see is because you are creating the tree widget
    with 5 columns but when you insert nodes into it, you provide data for
    only three columns.


    ttk::treeview $tw.tree -columns {fullpath type size date time} ... $tw.tree insert Folder end -text $key -values [list 80KB 18:00 21/09/2022]
    I don't know what your file list looks like (i.e., plain file names,
    full paths, a dictionary, etc.). But you can at least pass the file
    name and its type (may be ".ini"?) as the first two elements of the list:

    % $tw.tree insert Folder end -text $key -values [list $key ".ini" 80KB 18:00 21/09/2022]
    Yup (and Doh!), you are absolutely correct, I was passing only three elements.... for 5 columns. Apologies for overlooking the that bit...I shouldn't be working so late...

    Thank you saitology9

    So I did as suggested by saitology9,

    if I pass 3 variables to line $tw.tree insert Folder end -text $key -values [$key $key $s $t $d]

    where s, t and d are variables for size time and date created by reading files from a folder and processing to get the desired attributes.

    If I pass these to the $tw.tree insert Folder end -text $key -values [A B $s $t $d] which is within foreach loop, I only get the last value in the list for variables s, d and t

    for e.g. all entries for the files are populated with 80KB 18:00 21/09/2022

    Any advice.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to GeorgeB on Fri Sep 23 01:42:24 2022
    GeorgeB <[email protected]> wrote:
    So I did as suggested by saitology9,

    if I pass 3 variables to line $tw.tree insert Folder end -text $key
    -values [$key $key $s $t $d]

    where s, t and d are variables for size time and date created by
    reading files from a folder and processing to get the desired
    attributes.

    If I pass these to the $tw.tree insert Folder end -text $key -values
    [A B $s $t $d] which is within foreach loop, I only get the last
    value in the list for variables s, d and t

    for e.g. all entries for the files are populated with 80KB 18:00
    21/09/2022

    Any advice.

    Make sure your code is as above, and not as you posted a few articles
    ago:

    $tw.tree insert Folder end -text $key -values [list 80KB 18:00 21/09/2022]

    Your result implies you still have the constants in your source.

    Note also that the code you posted above is broken, it will not run.
    You'll get better answers if you check that your code you are about to
    post actually runs before you post it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to Rich on Fri Sep 23 01:03:38 2022
    On Friday, September 23, 2022 at 2:42:28 AM UTC+1, Rich wrote:
    GeorgeB <[email protected]> wrote:
    So I did as suggested by saitology9,

    if I pass 3 variables to line $tw.tree insert Folder end -text $key
    -values [$key $key $s $t $d]

    where s, t and d are variables for size time and date created by
    reading files from a folder and processing to get the desired
    attributes.

    If I pass these to the $tw.tree insert Folder end -text $key -values
    [A B $s $t $d] which is within foreach loop, I only get the last
    value in the list for variables s, d and t

    for e.g. all entries for the files are populated with 80KB 18:00
    21/09/2022

    Any advice.
    Make sure your code is as above, and not as you posted a few articles
    ago:
    $tw.tree insert Folder end -text $key -values [list 80KB 18:00 21/09/2022] Your result implies you still have the constants in your source.

    Note also that the code you posted above is broken, it will not run.
    You'll get better answers if you check that your code you are about to
    post actually runs before you post it.

    Hi Rich,

    Apologies, please see code.

    I must admit I don't fully understand procedures (need some basics), and I'm still working off examples.

    However in the process, I'm recreating code based on these examples (using them as guide/ reference).

    ##########################
    package require Tk

    unset -nocomplain ::fldr_lib

    set tw .tree
    catch {destroy $tw}
    toplevel $tw
    wm title $tw "Directory Browser"
    wm iconname $tw "tree"
    positionWindow $tw

    catch {console show}
    set rmDir "C:/"

    proc rglob { dirpath patterns {exclude_pats {}} } {
    set rlist {}
    set f_exclude [glob -nocomplain -types f -directory ${dirpath} {*}${exclude_pats}]
    set d_exclude [glob -nocomplain -types d -directory ${dirpath} {*}${exclude_pats}]
    foreach fpath [glob -nocomplain -types f -directory ${dirpath} {*}] {
    if { ${fpath} ni ${f_exclude} } {
    lappend rlist ${fpath}
    }
    }
    foreach dir [glob -nocomplain -types d -directory ${dirpath} *] {
    if { ${dir} ni ${d_exclude} } {
    lappend rlist {*}[rglob ${dir} ${patterns} ${exclude_pats}]
    }
    }
    return ${rlist}

    }
    # ##################################


    set ifname [rglob $rmDir *.ini {*.docx *.pptx *.txt *.xlsx}]

    foreach ::dir [lsort $ifname] {
    set split [file split $::dir]
    set ::nodeid [lindex $split end-1]
    set ::fname [lindex $split end-0]



    set ::size [file size $::dir]
    set ::ttime [file mtime $::dir]
    set ::date [clock format $::ttime -format "%d/%m/%Y"]
    set ::time [clock format $::ttime -format "%H:%M:%S"]

    if {$::size >= 1024*1024*1024} {
    set ::size [format %.1f\ GB [expr {$::size/1024/1024/1024.}]]
    } elseif {$::size >= 1024*1024} {
    set ::size [format %.1f\ MB [expr {$::size/1024/1024.}]]
    } elseif {$::size >= 1024} {
    set ::size [format %.1f\ kB [expr {$::size/1024.}]]
    } else {
    append ::size " bytes"
    append ::date " "
    append ::time " "
    }

    if {$::nodeid == "Folder"} {
    lappend ::fldr_lib $::fname
    #puts "Check within if statement $::fldr_lib"
    set ::f1NodeId $::nodeid
    set ::s $::size
    set ::t $::time
    set ::d $::date
    }
    }

    #puts "Check if all files are written in variable $::fldr_lib"

    ttk::treeview $tw.tree -columns {fullpath type size date time} -displaycolumns {size date time} -yscroll [list $tw.vsb set] -xscroll [list $tw.hsb set]
    ttk::scrollbar $tw.vsb -orient vertical -command "$tw.tree yview" ttk::scrollbar $tw.hsb -orient horizontal -command "$tw.tree xview"
    $tw.tree heading \#0 -text "Directory"
    $tw.tree column #0 -anchor e -minwidth 150 -width 250 -stretch 1
    $tw.tree heading size -text "Size"
    $tw.tree column size -stretch 0 -width 70
    $tw.tree heading time -text "Time"
    $tw.tree column time -stretch 0 -width 70
    $tw.tree heading date -text "Date"
    $tw.tree column date -stretch 0 -width 70


    $tw.tree insert {} end -id Folder -text "Folder"
    foreach key [lsort $::fldr_lib] {
    puts "Size $::s | Date $::d | Time $::t"
    $tw.tree insert Folder end -text $key -values [list $key $key $s $d $t]
    }

    lower [ttk::frame $tw.dummy]
    pack $tw.dummy -fill both -expand 1
    grid $tw.tree $tw.vsb -sticky nsew -in $tw.dummy
    grid $tw.hsb -sticky nsew -in $tw.dummy
    grid columnconfigure $tw.dummy 0 -weight 1
    grid rowconfigure $tw.dummy 0 -weight 1
    grid columnconfigure $tw 2 -weight 1
    grid rowconfigure $tw 2 -weight 1

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to GeorgeB on Fri Sep 23 12:37:03 2022
    GeorgeB <[email protected]> wrote:
    On Friday, September 23, 2022 at 2:42:28 AM UTC+1, Rich wrote:
    GeorgeB <[email protected]> wrote:
    So I did as suggested by saitology9,

    if I pass 3 variables to line $tw.tree insert Folder end -text $key
    -values [$key $key $s $t $d]

    where s, t and d are variables for size time and date created by
    reading files from a folder and processing to get the desired
    attributes.

    If I pass these to the $tw.tree insert Folder end -text $key -values
    [A B $s $t $d] which is within foreach loop, I only get the last
    value in the list for variables s, d and t

    for e.g. all entries for the files are populated with 80KB 18:00
    21/09/2022

    Any advice.
    Make sure your code is as above, and not as you posted a few articles
    ago:
    $tw.tree insert Folder end -text $key -values [list 80KB 18:00 21/09/2022] >> Your result implies you still have the constants in your source.

    Note also that the code you posted above is broken, it will not run.
    You'll get better answers if you check that your code you are about to
    post actually runs before you post it.

    Hi Rich,

    Apologies, please see code.

    Did you actually try running what you posted, *before* you posted it?

    I.e., did you put only what you posted here into a file, all alone, and
    try to launch it?

    Because the code you posted again *does not run*:

    Error in startup script: invalid command name "positionWindow"
    while executing
    "positionWindow $tw"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to Rich on Fri Sep 23 07:08:48 2022
    On Friday, September 23, 2022 at 1:37:07 PM UTC+1, Rich wrote:
    GeorgeB <[email protected]> wrote:
    On Friday, September 23, 2022 at 2:42:28 AM UTC+1, Rich wrote:
    GeorgeB <[email protected]> wrote:
    So I did as suggested by saitology9,

    if I pass 3 variables to line $tw.tree insert Folder end -text $key
    -values [$key $key $s $t $d]

    where s, t and d are variables for size time and date created by
    reading files from a folder and processing to get the desired
    attributes.

    If I pass these to the $tw.tree insert Folder end -text $key -values
    [A B $s $t $d] which is within foreach loop, I only get the last
    value in the list for variables s, d and t

    for e.g. all entries for the files are populated with 80KB 18:00
    21/09/2022

    Any advice.
    Make sure your code is as above, and not as you posted a few articles
    ago:
    $tw.tree insert Folder end -text $key -values [list 80KB 18:00 21/09/2022] >> Your result implies you still have the constants in your source.

    Note also that the code you posted above is broken, it will not run.
    You'll get better answers if you check that your code you are about to
    post actually runs before you post it.

    Hi Rich,

    Apologies, please see code.
    Did you actually try running what you posted, *before* you posted it?

    I.e., did you put only what you posted here into a file, all alone, and
    try to launch it?

    Because the code you posted again *does not run*:

    Error in startup script: invalid command name "positionWindow"
    while executing
    "positionWindow $tw"


    Yes I did, and I don't get the error, if I could I would provide a screenshot.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to All on Fri Sep 23 07:28:39 2022
    I'm coping the code again.

    ##########################
    package require Tk

    unset -nocomplain ::fldr_lib

    set tw .tree
    catch {destroy $tw}
    toplevel $tw
    wm title $tw "Directory Browser"
    wm iconname $tw "tree"
    positionWindow $tw

    catch {console show}
    set rmDir "C:/"

    proc rglob { dirpath patterns {exclude_pats {}} } {
    set rlist {}
    set f_exclude [glob -nocomplain -types f -directory ${dirpath} {*}${exclude_pats}]
    set d_exclude [glob -nocomplain -types d -directory ${dirpath} {*}${exclude_pats}]
    foreach fpath [glob -nocomplain -types f -directory ${dirpath} {*}] {
    if { ${fpath} ni ${f_exclude} } {
    lappend rlist ${fpath}
    }
    }
    foreach dir [glob -nocomplain -types d -directory ${dirpath} *] {
    if { ${dir} ni ${d_exclude} } {
    lappend rlist {*}[rglob ${dir} ${patterns} ${exclude_pats}]
    }
    }
    return ${rlist}

    }
    # ##################################


    set ifname [rglob $rmDir *.ini {*.docx *.pptx *.txt *.xlsx}]

    foreach ::dir [lsort $ifname] {
    set split [file split $::dir]
    set ::nodeid [lindex $split end-1]
    set ::fname [lindex $split end-0]



    set ::size [file size $::dir]
    set ::ttime [file mtime $::dir]
    set ::date [clock format $::ttime -format "%d/%m/%Y"]
    set ::time [clock format $::ttime -format "%H:%M:%S"]

    if {$::size >= 1024*1024*1024} {
    set ::size [format %.1f\ GB [expr {$::size/1024/1024/1024.}]]
    } elseif {$::size >= 1024*1024} {
    set ::size [format %.1f\ MB [expr {$::size/1024/1024.}]]
    } elseif {$::size >= 1024} {
    set ::size [format %.1f\ kB [expr {$::size/1024.}]]
    } else {
    append ::size " bytes"
    append ::date " "
    append ::time " "
    }

    if {$::nodeid == "Folder"} {
    lappend ::fldr_lib $::fname
    #puts "Check within if statement $::fldr_lib"
    set ::f1NodeId $::nodeid
    set ::s $::size
    set ::t $::time
    set ::d $::date
    }
    }

    #puts "Check if all files are written in variable $::fldr_lib"

    ttk::treeview $tw.tree -columns {fullpath type size date time} -displaycolumns {size date time} -yscroll [list $tw.vsb set] -xscroll [list $tw.hsb set]
    ttk::scrollbar $tw.vsb -orient vertical -command "$tw.tree yview" ttk::scrollbar $tw.hsb -orient horizontal -command "$tw.tree xview"
    $tw.tree heading \#0 -text "Directory"
    $tw.tree column #0 -anchor e -minwidth 150 -width 250 -stretch 1
    $tw.tree heading size -text "Size"
    $tw.tree column size -stretch 0 -width 70
    $tw.tree heading time -text "Time"
    $tw.tree column time -stretch 0 -width 70
    $tw.tree heading date -text "Date"
    $tw.tree column date -stretch 0 -width 70


    $tw.tree insert {} end -id Folder -text "Folder"
    foreach key [lsort $::fldr_lib] {
    puts "Size $::s | Date $::d | Time $::t"
    $tw.tree insert Folder end -text $key -values [list $key $key $s $d $t]
    }

    lower [ttk::frame $tw.dummy]
    pack $tw.dummy -fill both -expand 1
    grid $tw.tree $tw.vsb -sticky nsew -in $tw.dummy
    grid $tw.hsb -sticky nsew -in $tw.dummy
    grid columnconfigure $tw.dummy 0 -weight 1
    grid rowconfigure $tw.dummy 0 -weight 1
    grid columnconfigure $tw 2 -weight 1
    grid rowconfigure $tw 2 -weight 1

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From saitology9@21:1/5 to All on Fri Sep 23 13:59:33 2022
    On 9/23/22 1:55 PM, saitology9 wrote:
    On 9/23/22 10:28 AM, GeorgeB wrote:
    I'm coping the code again.


    Alternatively, search the wiki for file browsers.  There are several Tcl-only ones, and they will accept the option to limit the listings to certain files.



    You haven't mentioned any context around this but you may be perfectly h
    appy with a plain listbox. I would look into it as well.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to GeorgeB on Fri Sep 23 17:52:30 2022
    GeorgeB <[email protected]> wrote:
    I'm coping the code again.

    Are you testing against a 'clean' Tcl interpreter?

    Do this experiment:

    1) copy out the code from Usenet that you posted, into a brand new
    empty text file

    2) from a terminal, launch the text file this way:

    wish copied.txt

    And you'll get this error as well:

    Error in startup script: invalid command name "positionWindow"
    while executing
    "positionWindow $tw"
    (file "ott" line 11)

    Or, if you don't know how to open a windows terminal and do the
    launch, then open a brand new, clean, never before used, wish with
    console, and in that, clean, interpreter, do:

    source copied.txt

    Above I'm assuming you named the new text file "copied.txt" --
    substitute with whatever name you actually used.

    If you launch in an interpreter that you've previously used, then you
    have prior definitions of procs and/or variables that do not exist for
    us. You need to try launching the code the same way we have to, in a
    brand new, clean, interpreter.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From saitology9@21:1/5 to GeorgeB on Fri Sep 23 13:55:33 2022
    On 9/23/22 10:28 AM, GeorgeB wrote:
    I'm coping the code again.

    I am afraid it still doesn't run. You need to initialize "tw". It is
    easy fix it by setting it to empty string so it corresponds to the main toplevel window.


    set ifname [rglob $rmDir *.ini {*.docx *.pptx *.txt *.xlsx}]

    A side point, but you seem to have complicated your situation
    needlessly, at least at this point where you don't have a working
    version. If you are searching for a specific file type, all others will
    get eliminated automatically, right?


    foreach ::dir [lsort $ifname] {
    set split [file split $::dir]
    set ::nodeid [lindex $split end-1]
    set ::fname [lindex $split end-0]

    ..

    if {$::nodeid == "Folder"} {
    ..

    What you get in "nodeid" is not what you think it is.

    Also, you can't change or capitalize constants that are required by the commands and packages. I can guess you meant to compare the file type
    and see if it is a "folder". You can't capitalize it.


    My main recommendation would be 1) to review the basic language syntax,
    and then 2) to review the documentation of the treeview widget. Knowing
    the language does not translate to the packages. 3) You may be better
    off fixing the first version you posted instead of this latest one.
    Because to be honest, I do not see much influence in your code of the recommendations you have received so far. They should have helped you
    quite a bit.

    Alternatively, search the wiki for file browsers. There are several
    Tcl-only ones, and they will accept the option to limit the listings to
    certain files.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to All on Sat Sep 24 01:30:35 2022
    On Friday, September 23, 2022 at 6:59:38 PM UTC+1, saitology9 wrote:
    On 9/23/22 1:55 PM, saitology9 wrote:
    On 9/23/22 10:28 AM, GeorgeB wrote:
    I'm coping the code again.


    Alternatively, search the wiki for file browsers. There are several Tcl-only ones, and they will accept the option to limit the listings to certain files.


    You haven't mentioned any context around this but you may be perfectly h
    appy with a plain listbox. I would look into it as well.

    @Rich, ok I now understand..what I have been doing all this while is using the tree.tcl available in my activeState installation (C:\TCL\demos\Tk8.6)

    And have been modifying that file itself (backed up the original). So if I understand correctly that file references widget.tcl (also present in Demo Directory), maybe that initialises additional variables.

    @saitology9, I agree, I think I've messed up and should go back to my originally posted code, I've implemented all the recommendations in the original code.

    My rationale was (I'm still newbie), to may be re-write some bits in the hope of learning and then being able to also limit the files in the tree to only those with extension of *.ini, clearly lot to learn.

    Context around the code : generate a tree structure (or something similar) by looking a two folders, filter on *.ini files and dump user selection to a file.

    Using tree.tcl I can achieve all the steps expect filter on *.ini files. I should be able to achieve all the objectives but I'm struggling to understand proc{} , how they operate.

    hence attempted to re-write.

    The need to filter on *.ini is because there is no way to add checkbox or is tricky to add with treeview (or so I read), I did find some examples but looks quite daunting.

    Hope this explains.

    I'll have a look at listbox.

    Thanks in advance.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From saitology9@21:1/5 to GeorgeB on Sat Sep 24 23:31:14 2022
    On 9/24/22 4:30 AM, GeorgeB wrote:

    Context around the code : generate a tree structure (or something similar) by looking a two folders, filter on *.ini files and dump user selection to a file.

    Using tree.tcl I can achieve all the steps expect filter on *.ini files. I should be able to achieve all the objectives but I'm struggling to understand proc{} , how they operate.

    hence attempted to re-write.

    The need to filter on *.ini is because there is no way to add checkbox or is tricky to add with treeview (or so I read), I did find some examples but looks quite daunting.

    Hope this explains.

    I'll have a look at listbox.

    Thanks in advance.


    Here is a working prototype based on your initial code. You can create
    multiple trees displaying different folders, each with a different
    filter. It has some extra features that may be helpful such as
    auto-expansion for non-empty folders, color-coding, etc.

    You can see how proc's help you organize your code and make it reusable.
    I think *every* programming language has a similar construct.

    ----------------------------------------------------------------

    package req Tk


    proc populateRoots {tree ROOT SHOW_TYPES} {
    populateTree $tree \
    [$tree insert {} end -text "Network File" \
    -values [list $ROOT directory] \
    -open 1] \
    $SHOW_TYPES
    }

    ## Code to populate a node of the tree
    proc populateTree {tree node SHOW_TYPES} {

    if {[$tree set $node type] ne "directory"} {
    return
    }
    set path [$tree set $node fullpath]
    $tree delete [$tree children $node]



    ### display so that folders comes before files at the same level
    ### files and folders are displayed in alphabetical order
    set folders [lsort -dictionary [glob -nocomplain -type d -dir
    $path *]]
    set files [lsort -dictionary [glob -nocomplain -type f -dir
    $path *]]


    foreach f [list {*}$folders {*}$files] {
    set type [file type $f]
    if {$type eq "directory"} {
    ### this is a folder
    ### Make it so that this node is openable
    set id [$tree insert $node end -text [file tail $f] \
    -values [list $f $type] \
    -open 0]

    $tree insert $id 0 -text dummy ;# a dummy
    $tree item $id -text [file tail $f]/


    ### this folder has sub-folders
    ### process them automatically
    ### so the user does not have to click on each one
    ### to find where actual files are
    populateTree $tree $id $SHOW_TYPES

    } elseif {($type eq "file") && \
    ([file extension $f] in $SHOW_TYPES)} {


    ### get basic info on the file to display

    ### Format the file size nicely
    set size [file size $f]
    if {$size >= 1024*1024*1024} {
    set size [format %.1f\ GB [expr {$size/1024/1024/1024.}]]
    } elseif {$size >= 1024*1024} {
    set size [format %.1f\ MB [expr {$size/1024/1024.}]]
    } elseif {$size >= 1024} {
    set size [format %.1f\ kB [expr {$size/1024.}]]
    } else {
    append size " bytes"
    }


    ### format the date and time nicely
    set ttime [file mtime $f]
    set fdate [clock format $ttime -format "%Y-%m-%d"]
    set ftime [clock format $ttime -format "%H-%M-%S"]


    ### display the file in the tree
    set id [$tree insert $node end \
    -tags SHOW_FILE \
    -text [file tail $f] \
    -values [list $f $type $size $fdate $ftime]]


    ### only open folders that are not empty
    ### THIS FOLDER HAS A DISPLAYABLE FILE IN IT
    ### AUTOMATICALLY OPEN IT
    $tree set $id size $size
    $tree item [$tree parent $id] -open 1 -tags FOLDER_HAS_ITEM

    } else {
    # a file type that will not be shown
    }
    }


    # Stop this code from rerunning on the current node
    $tree set $node type processedDirectory
    }


    # ## Create the tree and set it up
    proc display_tree {tw ROOT SHOW_TYPES} {
    catch { destroy $tw.tree }
    catch { destroy $tw.vsb }
    catch { destroy $tw.hsb }
    catch { destroy $tw.dummy }

    ttk::treeview $tw.tree -columns {fullpath type size date time} \
    -displaycolumns {size date time} \
    -yscroll "$tw.vsb set" -xscroll "$tw.hsb set"
    ttk::scrollbar $tw.vsb -orient vertical -command "$tw.tree yview"
    ttk::scrollbar $tw.hsb -orient horizontal -command "$tw.tree xview"

    $tw.tree heading \#0 -text "Directory Structure"
    $tw.tree heading size -text "File Size" -anchor w
    $tw.tree heading date -text "Last Mod Date" -anchor w
    $tw.tree heading time -text "Last Mod Time" -anchor w

    $tw.tree column size -stretch 1 -width 20
    $tw.tree column date -stretch 1 -width 20
    $tw.tree column time -stretch 1 -width 20


    ### you can make files and non-empty folders more visible
    ### by playing around with colors and fonts as below
    ### change or remove as needed
    $tw.tree tag config SHOW_FILE -foreground blue -font bold
    $tw.tree tag config FOLDER_HAS_ITEM -foreground red -font bold


    populateRoots $tw.tree $ROOT $SHOW_TYPES
    bind $tw.tree <<TreeviewOpen>> {populateTree %W [%W focus]
    $SHOW_TYPES}


    # ## Arrange the tree and its scrollbars in the toplevel
    lower [ttk::frame $tw.dummy]


    pack $tw.dummy -fill both -expand 1


    grid $tw.tree $tw.vsb -sticky nsew -in $tw.dummy
    grid $tw.hsb -sticky nsew -in $tw.dummy
    grid columnconfigure $tw.dummy 0 -weight 1
    grid rowconfigure $tw.dummy 0 -weight 1
    }


    proc run_test {} {

    wm iconify .


    ### first window
    set ROOT_1 "C:/Dev"
    set SHOW_TYPES [list .ini .txt .docx]


    catch {destroy .t1 }
    toplevel .t1
    wm title .t1 $ROOT_1
    wm geom .t1 500x400

    display_tree .t1 $ROOT_1 $SHOW_TYPES


    ### second window with different files to show
    set ROOT_2 "C:/Windows/INF"
    set SHOW_TYPES [list .ini .csv]

    catch {destroy .t2 }
    toplevel .t2
    wm title .t2 $ROOT_2
    wm geom .t2 800x600

    display_tree .t2 $ROOT_2 $SHOW_TYPES
    }


    ### start here
    run_test

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to All on Sun Sep 25 13:22:44 2022
    On Sunday, September 25, 2022 at 4:31:21 AM UTC+1, saitology9 wrote:
    On 9/24/22 4:30 AM, GeorgeB wrote:

    Context around the code : generate a tree structure (or something similar) by looking a two folders, filter on *.ini files and dump user selection to a file.

    Using tree.tcl I can achieve all the steps expect filter on *.ini files. I should be able to achieve all the objectives but I'm struggling to understand proc{} , how they operate.

    hence attempted to re-write.

    The need to filter on *.ini is because there is no way to add checkbox or is tricky to add with treeview (or so I read), I did find some examples but looks quite daunting.

    Hope this explains.

    I'll have a look at listbox.

    Thanks in advance.
    Here is a working prototype based on your initial code. You can create multiple trees displaying different folders, each with a different
    filter. It has some extra features that may be helpful such as
    auto-expansion for non-empty folders, color-coding, etc.

    You can see how proc's help you organize your code and make it reusable.
    I think *every* programming language has a similar construct.

    ----------------------------------------------------------------

    package req Tk


    proc populateRoots {tree ROOT SHOW_TYPES} {
    populateTree $tree \
    [$tree insert {} end -text "Network File" \
    -values [list $ROOT directory] \
    -open 1] \
    $SHOW_TYPES
    }

    ## Code to populate a node of the tree
    proc populateTree {tree node SHOW_TYPES} {

    if {[$tree set $node type] ne "directory"} {
    return
    }
    set path [$tree set $node fullpath]
    $tree delete [$tree children $node]



    ### display so that folders comes before files at the same level
    ### files and folders are displayed in alphabetical order
    set folders [lsort -dictionary [glob -nocomplain -type d -dir
    $path *]]
    set files [lsort -dictionary [glob -nocomplain -type f -dir
    $path *]]


    foreach f [list {*}$folders {*}$files] {
    set type [file type $f]
    if {$type eq "directory"} {
    ### this is a folder
    ### Make it so that this node is openable
    set id [$tree insert $node end -text [file tail $f] \
    -values [list $f $type] \
    -open 0]

    $tree insert $id 0 -text dummy ;# a dummy
    $tree item $id -text [file tail $f]/


    ### this folder has sub-folders
    ### process them automatically
    ### so the user does not have to click on each one
    ### to find where actual files are
    populateTree $tree $id $SHOW_TYPES

    } elseif {($type eq "file") && \
    ([file extension $f] in $SHOW_TYPES)} {


    ### get basic info on the file to display

    ### Format the file size nicely
    set size [file size $f]
    if {$size >= 1024*1024*1024} {
    set size [format %.1f\ GB [expr {$size/1024/1024/1024.}]]
    } elseif {$size >= 1024*1024} {
    set size [format %.1f\ MB [expr {$size/1024/1024.}]]
    } elseif {$size >= 1024} {
    set size [format %.1f\ kB [expr {$size/1024.}]]
    } else {
    append size " bytes"
    }


    ### format the date and time nicely
    set ttime [file mtime $f]
    set fdate [clock format $ttime -format "%Y-%m-%d"]
    set ftime [clock format $ttime -format "%H-%M-%S"]


    ### display the file in the tree
    set id [$tree insert $node end \
    -tags SHOW_FILE \
    -text [file tail $f] \
    -values [list $f $type $size $fdate $ftime]]


    ### only open folders that are not empty
    ### THIS FOLDER HAS A DISPLAYABLE FILE IN IT
    ### AUTOMATICALLY OPEN IT
    $tree set $id size $size
    $tree item [$tree parent $id] -open 1 -tags FOLDER_HAS_ITEM

    } else {
    # a file type that will not be shown
    }
    }


    # Stop this code from rerunning on the current node
    $tree set $node type processedDirectory
    }


    # ## Create the tree and set it up
    proc display_tree {tw ROOT SHOW_TYPES} {
    catch { destroy $tw.tree }
    catch { destroy $tw.vsb }
    catch { destroy $tw.hsb }
    catch { destroy $tw.dummy }
    ttk::treeview $tw.tree -columns {fullpath type size date time} \ -displaycolumns {size date time} \
    -yscroll "$tw.vsb set" -xscroll "$tw.hsb set"
    ttk::scrollbar $tw.vsb -orient vertical -command "$tw.tree yview" ttk::scrollbar $tw.hsb -orient horizontal -command "$tw.tree xview"
    $tw.tree heading \#0 -text "Directory Structure"
    $tw.tree heading size -text "File Size" -anchor w
    $tw.tree heading date -text "Last Mod Date" -anchor w
    $tw.tree heading time -text "Last Mod Time" -anchor w

    $tw.tree column size -stretch 1 -width 20
    $tw.tree column date -stretch 1 -width 20
    $tw.tree column time -stretch 1 -width 20


    ### you can make files and non-empty folders more visible
    ### by playing around with colors and fonts as below
    ### change or remove as needed
    $tw.tree tag config SHOW_FILE -foreground blue -font bold
    $tw.tree tag config FOLDER_HAS_ITEM -foreground red -font bold


    populateRoots $tw.tree $ROOT $SHOW_TYPES
    bind $tw.tree <<TreeviewOpen>> {populateTree %W [%W focus]
    $SHOW_TYPES}


    # ## Arrange the tree and its scrollbars in the toplevel
    lower [ttk::frame $tw.dummy]


    pack $tw.dummy -fill both -expand 1


    grid $tw.tree $tw.vsb -sticky nsew -in $tw.dummy
    grid $tw.hsb -sticky nsew -in $tw.dummy
    grid columnconfigure $tw.dummy 0 -weight 1
    grid rowconfigure $tw.dummy 0 -weight 1
    }
    proc run_test {} {

    wm iconify .


    ### first window
    set ROOT_1 "C:/Dev"
    set SHOW_TYPES [list .ini .txt .docx]


    catch {destroy .t1 }
    toplevel .t1
    wm title .t1 $ROOT_1
    wm geom .t1 500x400

    display_tree .t1 $ROOT_1 $SHOW_TYPES


    ### second window with different files to show
    set ROOT_2 "C:/Windows/INF"
    set SHOW_TYPES [list .ini .csv]

    catch {destroy .t2 }
    toplevel .t2
    wm title .t2 $ROOT_2
    wm geom .t2 800x600

    display_tree .t2 $ROOT_2 $SHOW_TYPES
    }


    ### start here
    run_test

    @saitology9 Thank you so much, this worked wonderfully. Very much appreciated...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to GeorgeB on Mon Sep 26 11:27:44 2022
    On Sunday, September 25, 2022 at 9:22:46 PM UTC+1, GeorgeB wrote:
    On Sunday, September 25, 2022 at 4:31:21 AM UTC+1, saitology9 wrote:
    On 9/24/22 4:30 AM, GeorgeB wrote:

    Context around the code : generate a tree structure (or something similar) by looking a two folders, filter on *.ini files and dump user selection to a file.

    Using tree.tcl I can achieve all the steps expect filter on *.ini files. I should be able to achieve all the objectives but I'm struggling to understand proc{} , how they operate.

    hence attempted to re-write.

    The need to filter on *.ini is because there is no way to add checkbox or is tricky to add with treeview (or so I read), I did find some examples but looks quite daunting.

    Hope this explains.

    I'll have a look at listbox.

    Thanks in advance.
    Here is a working prototype based on your initial code. You can create multiple trees displaying different folders, each with a different
    filter. It has some extra features that may be helpful such as auto-expansion for non-empty folders, color-coding, etc.

    You can see how proc's help you organize your code and make it reusable.
    I think *every* programming language has a similar construct.

    ----------------------------------------------------------------

    package req Tk


    proc populateRoots {tree ROOT SHOW_TYPES} {
    populateTree $tree \
    [$tree insert {} end -text "Network File" \
    -values [list $ROOT directory] \
    -open 1] \
    $SHOW_TYPES
    }

    ## Code to populate a node of the tree
    proc populateTree {tree node SHOW_TYPES} {

    if {[$tree set $node type] ne "directory"} {
    return
    }
    set path [$tree set $node fullpath]
    $tree delete [$tree children $node]



    ### display so that folders comes before files at the same level
    ### files and folders are displayed in alphabetical order
    set folders [lsort -dictionary [glob -nocomplain -type d -dir
    $path *]]
    set files [lsort -dictionary [glob -nocomplain -type f -dir
    $path *]]


    foreach f [list {*}$folders {*}$files] {
    set type [file type $f]
    if {$type eq "directory"} {
    ### this is a folder
    ### Make it so that this node is openable
    set id [$tree insert $node end -text [file tail $f] \
    -values [list $f $type] \
    -open 0]

    $tree insert $id 0 -text dummy ;# a dummy
    $tree item $id -text [file tail $f]/


    ### this folder has sub-folders
    ### process them automatically
    ### so the user does not have to click on each one
    ### to find where actual files are
    populateTree $tree $id $SHOW_TYPES

    } elseif {($type eq "file") && \
    ([file extension $f] in $SHOW_TYPES)} {


    ### get basic info on the file to display

    ### Format the file size nicely
    set size [file size $f]
    if {$size >= 1024*1024*1024} {
    set size [format %.1f\ GB [expr {$size/1024/1024/1024.}]]
    } elseif {$size >= 1024*1024} {
    set size [format %.1f\ MB [expr {$size/1024/1024.}]]
    } elseif {$size >= 1024} {
    set size [format %.1f\ kB [expr {$size/1024.}]]
    } else {
    append size " bytes"
    }


    ### format the date and time nicely
    set ttime [file mtime $f]
    set fdate [clock format $ttime -format "%Y-%m-%d"]
    set ftime [clock format $ttime -format "%H-%M-%S"]


    ### display the file in the tree
    set id [$tree insert $node end \
    -tags SHOW_FILE \
    -text [file tail $f] \
    -values [list $f $type $size $fdate $ftime]]


    ### only open folders that are not empty
    ### THIS FOLDER HAS A DISPLAYABLE FILE IN IT
    ### AUTOMATICALLY OPEN IT
    $tree set $id size $size
    $tree item [$tree parent $id] -open 1 -tags FOLDER_HAS_ITEM

    } else {
    # a file type that will not be shown
    }
    }


    # Stop this code from rerunning on the current node
    $tree set $node type processedDirectory
    }


    # ## Create the tree and set it up
    proc display_tree {tw ROOT SHOW_TYPES} {
    catch { destroy $tw.tree }
    catch { destroy $tw.vsb }
    catch { destroy $tw.hsb }
    catch { destroy $tw.dummy }
    ttk::treeview $tw.tree -columns {fullpath type size date time} \ -displaycolumns {size date time} \
    -yscroll "$tw.vsb set" -xscroll "$tw.hsb set"
    ttk::scrollbar $tw.vsb -orient vertical -command "$tw.tree yview" ttk::scrollbar $tw.hsb -orient horizontal -command "$tw.tree xview" $tw.tree heading \#0 -text "Directory Structure"
    $tw.tree heading size -text "File Size" -anchor w
    $tw.tree heading date -text "Last Mod Date" -anchor w
    $tw.tree heading time -text "Last Mod Time" -anchor w

    $tw.tree column size -stretch 1 -width 20
    $tw.tree column date -stretch 1 -width 20
    $tw.tree column time -stretch 1 -width 20


    ### you can make files and non-empty folders more visible
    ### by playing around with colors and fonts as below
    ### change or remove as needed
    $tw.tree tag config SHOW_FILE -foreground blue -font bold
    $tw.tree tag config FOLDER_HAS_ITEM -foreground red -font bold


    populateRoots $tw.tree $ROOT $SHOW_TYPES
    bind $tw.tree <<TreeviewOpen>> {populateTree %W [%W focus]
    $SHOW_TYPES}


    # ## Arrange the tree and its scrollbars in the toplevel
    lower [ttk::frame $tw.dummy]


    pack $tw.dummy -fill both -expand 1


    grid $tw.tree $tw.vsb -sticky nsew -in $tw.dummy
    grid $tw.hsb -sticky nsew -in $tw.dummy
    grid columnconfigure $tw.dummy 0 -weight 1
    grid rowconfigure $tw.dummy 0 -weight 1
    }
    proc run_test {} {

    wm iconify .


    ### first window
    set ROOT_1 "C:/Dev"
    set SHOW_TYPES [list .ini .txt .docx]


    catch {destroy .t1 }
    toplevel .t1
    wm title .t1 $ROOT_1
    wm geom .t1 500x400

    display_tree .t1 $ROOT_1 $SHOW_TYPES


    ### second window with different files to show
    set ROOT_2 "C:/Windows/INF"
    set SHOW_TYPES [list .ini .csv]

    catch {destroy .t2 }
    toplevel .t2
    wm title .t2 $ROOT_2
    wm geom .t2 800x600

    display_tree .t2 $ROOT_2 $SHOW_TYPES
    }


    ### start here
    run_test
    @saitology9 Thank you so much, this worked wonderfully. Very much appreciated...

    Hello all, Thanks to saitology9 I've got a bit of head start.

    I was wondering if adding a checkbox to the tree would be a good idea or would it over complicate things.

    Looking at threads on the same topic, I realise it is not so easy unless I use treectrl etc.

    But I read that one can use image of checkbox, below is saitology9's corrections and updates. I've added a checkbox to each item.

    Question:
    If I want to user to make a selection with mouse either selection top level or individual items (at same time toggle the image). Would I need to bind "<ButtonPress-1>" to selection?



    package req Tk


    image create photo ::img::cb(0) -data {
    R0lGODlhDwAPANUAANnZ2Y6Pj/T09K6zua+0urS5vbu+wcvP1dDT2NXY3Nvd38HDxc3R1tLV2tjb
    3t3f4eLj5MbHyM3R19DU2dTX2+Hi4+Xm5ujo6MzNzbK3vNrc3+Dh4+zs7O3t7dTV1ri7v+Tl5erq
    6u/v7/Ly8tzd3ry/wuPk5enp6fX19eHi4sLExvDw8Pb29ubm5srLzNTU1dvb3ODh4ebn5+rr6+vs
    7Ovr7Onp6v///////////////////////////////////yH5BAEAAAAALAAAAAAPAA8AAAZvQIBw
    SCwCAsikMikMCJ7QqCDQFAyuWELBMK0ODuADIqFYdI9WMKPheEAiZ+dAMqEoKpYLJi7IJDQbFxwd
    HR58Hw8gISIjjSR8JSYnHSMCKAIpfCqTKwIsny18Li8wMTIzNDU2fFJSVEdLsa9GtABBADs=} image create photo ::img::cb(1) -data {
    R0lGODlhDwAPAOYAANnZ2Y6Pj/T09Pj4+Pn5+fb29q6zucnM0J2nwHeGq9zf5PX19cvP1czQ1u3u
    8VdqnURakrm/0M3R1uDi5q+4z0VakmV3pefn6NXZ3d/i5dXY3PLz9F5xoUdclLzD1tvc3MXJzcnP
    3aOuyO3u7rrB1UlelmR2pdXV1t7g4W5/qs/U4md4p0tgl7e/1dzd3s3P0d7h6UhdlUlflmFzpPj5
    +uHi4sbIyurs8IuZu0pfl0xhmLC50ebm5srLzNra29/i6YyZupCdvfLz9uzt7evr7Onp6v//////
    ////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////yH5
    BAEAAAAALAAAAAAPAA8AAAeFgACCg4SFAAGIiYqJggECj5ACAwQFAgGNAgaamgcICQoLl4eZDKUN
    Dg8QEQWijgalEhMUFRYXlpgGGBkaGxwdHh+3oyAhIiMkJSYDJ8KOKCkdKissLQUuzQIvMDEyLDM0
    AjXYNjc4OTo7lDzYPT4/QEFCQ0RF2I8LBAMLka2L/qKGAgIIBAA7}


    proc populateRoots {tree ROOT SHOW_TYPES} {
    populateTree $tree \
    [$tree insert {} end -text "Network File" \
    -values [list $ROOT directory] \
    -open 1] \
    $SHOW_TYPES
    }

    ## Code to populate a node of the tree
    proc populateTree {tree node SHOW_TYPES} {

    if {[$tree set $node type] ne "directory"} {
    return
    }
    set path [$tree set $node fullpath]
    $tree delete [$tree children $node]



    ### display so that folders comes before files at the same level
    ### files and folders are displayed in alphabetical order
    set folders [lsort -dictionary [glob -nocomplain -type d -dir \
    $path *]]
    set files [lsort -dictionary [glob -nocomplain -type f -dir \
    $path *]]


    foreach f [list {*}$folders {*}$files] {
    set type [file type $f]
    if {$type eq "directory"} {
    ### this is a folder
    ### Make it so that this node is openable
    set id [$tree insert $node end -text [file tail $f] \
    -values [list $f $type] \
    -open 0 \
    -image ::img::cb(0)]

    $tree insert $id 0 -text dummy ;# a dummy
    $tree item $id -text [file tail $f]/


    ### this folder has sub-folders
    ### process them automatically
    ### so the user does not have to click on each one
    ### to find where actual files are
    populateTree $tree $id $SHOW_TYPES

    } elseif {($type eq "file") && \
    ([file extension $f] in $SHOW_TYPES)} {


    ### get basic info on the file to display

    ### Format the file size nicely
    set size [file size $f]
    if {$size >= 1024*1024*1024} {
    set size [format %.1f\ GB [expr {$size/1024/1024/1024.}]]
    } elseif {$size >= 1024*1024} {
    set size [format %.1f\ MB [expr {$size/1024/1024.}]]
    } elseif {$size >= 1024} {
    set size [format %.1f\ kB [expr {$size/1024.}]]
    } else {
    append size " bytes"
    }


    ### format the date and time nicely
    set ttime [file mtime $f]
    set fdate [clock format $ttime -format "%Y-%m-%d"]
    set ftime [clock format $ttime -format "%H-%M-%S"]


    ### display the file in the tree
    set id [$tree insert $node end \
    -tags SHOW_FILE \
    -text [file tail $f] \
    -values [list $f $type $size $fdate $ftime] \
    -image ::img::cb(0)]


    ### only open folders that are not empty
    ### THIS FOLDER HAS A DISPLAYABLE FILE IN IT
    ### AUTOMATICALLY OPEN IT
    $tree set $id size $size
    $tree item [$tree parent $id] -open 1 -tags FOLDER_HAS_ITEM

    } else {
    # a file type that will not be shown
    }
    }


    # Stop this code from rerunning on the current node
    $tree set $node type processedDirectory
    }


    # ## Create the tree and set it up
    proc display_tree {tw ROOT SHOW_TYPES} {
    catch { destroy $tw.tree }
    catch { destroy $tw.vsb }
    catch { destroy $tw.hsb }
    catch { destroy $tw.dummy }

    ttk::treeview $tw.tree -columns {fullpath type size date time} \ -displaycolumns {size date time} \
    -yscroll "$tw.vsb set" -xscroll "$tw.hsb set"
    ttk::scrollbar $tw.vsb -orient vertical -command "$tw.tree yview" ttk::scrollbar $tw.hsb -orient horizontal -command "$tw.tree xview"

    $tw.tree heading \#0 -text "Directory Structure"
    $tw.tree heading size -text "File Size" -anchor w
    $tw.tree heading date -text "Last Mod Date" -anchor w
    $tw.tree heading time -text "Last Mod Time" -anchor w

    $tw.tree column size -stretch 1 -width 20
    $tw.tree column date -stretch 1 -width 20
    $tw.tree column time -stretch 1 -width 20


    ### you can make files and non-empty folders more visible
    ### by playing around with colors and fonts as below
    ### change or remove as needed
    $tw.tree tag config SHOW_FILE -foreground blue -font bold
    $tw.tree tag config FOLDER_HAS_ITEM -foreground red -font bold


    populateRoots $tw.tree $ROOT $SHOW_TYPES
    bind $tw.tree <<TreeviewOpen>> {populateTree %W [%W focus]
    $SHOW_TYPES}


    # ## Arrange the tree and its scrollbars in the toplevel
    lower [ttk::frame $tw.dummy]


    pack $tw.dummy -fill both -expand 1


    grid $tw.tree $tw.vsb -sticky nsew -in $tw.dummy
    grid $tw.hsb -sticky nsew -in $tw.dummy
    grid columnconfigure $tw.dummy 0 -weight 1
    grid rowconfigure $tw.dummy 0 -weight 1


    }


    proc run_test {} {

    wm iconify .


    ### first window
    set ROOT_1 "C:/Dev"
    set SHOW_TYPES [list .ini .txt .docx]


    catch {destroy .t1 }
    toplevel .t1
    wm title .t1 $ROOT_1
    wm geom .t1 500x400

    display_tree .t1 $ROOT_1 $SHOW_TYPES


    ### second window with different files to show
    set ROOT_2 "C:/Network_Files"
    set SHOW_TYPES [list .ini .csv]

    catch {destroy .t2 }
    toplevel .t2
    wm title .t2 $ROOT_2
    wm geom .t2 800x600

    display_tree .t2 $ROOT_2 $SHOW_TYPES
    }


    ### start here
    run_test

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From saitology9@21:1/5 to GeorgeB on Mon Sep 26 18:31:13 2022
    On 9/26/22 2:27 PM, GeorgeB wrote:

    I was wondering if adding a checkbox to the tree would be a good idea or would it over complicate things.

    ..

    But I read that one can use image of checkbox
    ..

    Question:
    If I want to user to make a selection with mouse either selection top level or individual items (at same time toggle the image). Would I need to bind "<ButtonPress-1>" to selection?


    I haven't used this widget before so I can't help you there. But you
    should be able to select multiple items as per usual MS Windows
    conventions: shift-click and control-click to select/de-select multiple
    items, and then get the items via the "$tw selection" command.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From GeorgeB@21:1/5 to All on Tue Sep 27 10:37:46 2022
    On Monday, September 26, 2022 at 11:31:36 PM UTC+1, saitology9 wrote:
    On 9/26/22 2:27 PM, GeorgeB wrote:

    I was wondering if adding a checkbox to the tree would be a good idea or would it over complicate things.

    ..

    But I read that one can use image of checkbox
    ..

    Question:
    If I want to user to make a selection with mouse either selection top level or individual items (at same time toggle the image). Would I need to bind "<ButtonPress-1>" to selection?

    I haven't used this widget before so I can't help you there. But you
    should be able to select multiple items as per usual MS Windows
    conventions: shift-click and control-click to select/de-select multiple items, and then get the items via the "$tw selection" command.

    So basically I would like to add a checkbox so that it toggles upon selection, I don't think treeview widget supports checkbox widget. Therefore thought it would be easier to add an image of checkbox selection which toggles.

    To be honest I'm not sure if I've added the image of the checkbox correctly, should it be in a column of its own?

    I'm also wondering if I can toggle the image of the checkbox from on to off upon selection of item in tree (children only).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)