• Flummoxed by foreach behavior

    From Luc@21:1/5 to All on Tue Oct 25 02:13:53 2022
    bind $::widget <Key-1> {set ::widget::choice $i; puts $::widget::choice}
    bind $::widget <Key-2> {set ::widget::choice $i; puts $::widget::choice}
    bind $::widget <Key-3> {set ::widget::choice $i; puts $::widget::choice}
    bind $::widget <Key-4> {set ::widget::choice $i; puts $::widget::choice}

    This works fine.
    I press 1, the app outputs 1. I press 2, the app outputs 2.
    And so on.

    However,

    foreach i {1 2 3 4 5 6 7 8 9 0} {
    bind $::widget <Key-$i> {set ::widget::choice $i; puts $::widget::choice}
    }

    I press 1, the app outputs 0. I press 2, the app outputs 0.
    I press 3, the app outputs 0.
    And so on.

    The output always is the last item in the list. I tested that.

    What in the blue blazes? I am completely stumped.

    TIA

    --
    Luc


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Harald Oehlmann@21:1/5 to All on Tue Oct 25 10:37:31 2022
    Am 25.10.2022 um 07:13 schrieb Luc:
    bind $::widget <Key-1> {set ::widget::choice $i; puts $::widget::choice}
    bind $::widget <Key-2> {set ::widget::choice $i; puts $::widget::choice}
    bind $::widget <Key-3> {set ::widget::choice $i; puts $::widget::choice}
    bind $::widget <Key-4> {set ::widget::choice $i; puts $::widget::choice}

    This works fine.
    I press 1, the app outputs 1. I press 2, the app outputs 2.
    And so on.

    However,

    foreach i {1 2 3 4 5 6 7 8 9 0} {
    bind $::widget <Key-$i> {set ::widget::choice $i; puts $::widget::choice}
    }

    I press 1, the app outputs 0. I press 2, the app outputs 0.
    I press 3, the app outputs 0.
    And so on.

    The output always is the last item in the list. I tested that.

    What in the blue blazes? I am completely stumped.

    TIA


    What about this :

    foreach i {1 2 3 4 5 6 7 8 9 0} {
    bind $::widget <Key-$i> "set ::widget::choice $i; puts \$::widget::choice"
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ralf Fassel@21:1/5 to All on Tue Oct 25 12:06:07 2022
    * Luc <no@no.no>
    | bind $::widget <Key-1> {set ::widget::choice $i; puts $::widget::choice}
    | bind $::widget <Key-2> {set ::widget::choice $i; puts $::widget::choice}
    | bind $::widget <Key-3> {set ::widget::choice $i; puts $::widget::choice}
    | bind $::widget <Key-4> {set ::widget::choice $i; puts $::widget::choice}

    | This works fine.
    | I press 1, the app outputs 1. I press 2, the app outputs 2.

    I don't believe that.

    $ wish
    % set widget [label .l -text "Click on me"]
    % pack $widget
    % focus $widget
    % bind $::widget <Key-1> {set ::widget::choice $i; puts $::widget::choice}
    now press "1"
    => error: so such variable: i

    | foreach i {1 2 3 4 5 6 7 8 9 0} {
    | bind $::widget <Key-$i> {set ::widget::choice $i; puts $::widget::choice}
    | }

    | I press 1, the app outputs 0. I press 2, the app outputs 0.
    | I press 3, the app outputs 0.
    | And so on.

    You need to understand what the 'bind' command is doing: it sets up a
    command to run later when the Event occurs.
    Now in your case, since the command is enclosed in {}, there is no
    variable substitution at the bind call.
    Rather the substitution takes place later when the event occurs.
    Confirm:

    % bind $::widget <Key-1>
    => set ::widget::choice $i; puts $::widget::choice
    % bind $::widget <Key-2>
    => set ::widget::choice $i; puts $::widget::choice
    ...

    Note how the $i is still there in all cases, it was not replaced when
    the bind was set up. Since in my test there was no variable 'i', I get
    the error. In your test, the loop variable 'i' was last set to 0, so
    this is what you see in all cases.

    Solutions:

    Check the available %-replacements for bind (most likely %K)

    use 'list' to set up the binding if the variables should get resolved
    when the bind is set:
    bind ... "[list set ::widget::choice $i] ; puts \$::widget::choice"

    for anything more substantial than a 'puts', use a helper proc to
    call when the event happens:

    proc some_action {key} {
    switch -- $key {
    1 - 2 - 3 - 4 {
    puts "key $key"
    }
    5 {
    puts "nononono!"
    }
    default {
    puts "don't know what to do with $key"
    }
    }
    }
    foreach k {1 2 3 4 5} {
    bind $widget <Key-$k> [list some_action %K]
    }
    # or even
    bind $widget <KeyPress> [list some_action %K]

    HTH
    R'

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