• Tk text tag bind issue with Tcl/Tk 8.6

    From Andy Maleh@21:1/5 to All on Sat Nov 6 09:11:07 2021
    I reported this issue at the ActiveState forum and Ruby Tk project:

    https://community.activestate.com/t/tk-text-tag-bind-issue-with-activetcl-8-6-occurs-when-using-tk-in-both-ruby-and-python/7665

    https://github.com/ruby/tk/issues/40

    Basically, using the tk::text widget, I bind '<KeyPress>' to a tag called 'all' covering '1.0' till 'end'. The goal is to track insert mark movement via arrow keys (and page-up/page-down/home/end). It works until I decide to highlight all text, delete it,
    and enter new text. Afterwards, the binding does not fire any events. But, after I enter a number of newlines, sometimes it starts firing again (unreliable as a workaround).

    Help is appreciated. Or perhaps a recommendation for where else to report this if this is not the right place to mention.

    Cheers.

    Andy Maleh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Andy Maleh on Sat Nov 6 16:56:39 2021
    Andy Maleh <andy.am@gmail.com> wrote:
    Basically, using the tk::text widget, I bind '<KeyPress>' to a tag
    called 'all' covering '1.0' till 'end'. The goal is to track insert
    mark movement via arrow keys (and page-up/page-down/home/end). It
    works until I decide to highlight all text, delete it, and enter new
    text. Afterwards, the binding does not fire any events. But, after
    I enter a number of newlines, sometimes it starts firing again
    (unreliable as a workaround).

    As an alternate, you can bind <KeyPress> on the widget itself and then
    filter for just the keys you are interested in, ignoring the remainder.
    Binding to the widget itself will mean the event should be unaffected
    by changes within the text widget contents.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Andy Maleh on Sat Nov 6 18:56:05 2021
    Andy Maleh <andy.am@gmail.com> wrote:
    On Saturday, November 6, 2021 at 12:56:43 PM UTC-4, Rich wrote:
    Andy Maleh wrote:
    Basically, using the tk::text widget, I bind '<KeyPress>' to a tag
    called 'all' covering '1.0' till 'end'. The goal is to track insert
    mark movement via arrow keys (and page-up/page-down/home/end). It
    works until I decide to highlight all text, delete it, and enter new
    text. Afterwards, the binding does not fire any events. But, after
    I enter a number of newlines, sometimes it starts firing again
    (unreliable as a workaround).
    As an alternate, you can bind <KeyPress> on the widget itself and then
    filter for just the keys you are interested in, ignoring the remainder.
    Binding to the widget itself will mean the event should be unaffected
    by changes within the text widget contents.

    Actually, what you suggest is what I tried first, but I noticed that
    none of the standard events (e.g. <KeyPress>, <ButtonPress>, etc...)
    work on the text widget directly. Only when binding to a tag, they
    work.

    I guess that is another bug to report: binding to standard events
    like <KeyPress> does not work on text.

    Binding to standard events work just fine on a text text widget:

    $ rlwrap wish
    % text .t
    .t
    % pack .t
    % focus .t
    % proc fire {args} {
    puts "binding fired args = $args"
    }
    % bind .t <KeyPress> [list fire %K]
    % binding fired args = a
    binding fired args = b
    binding fired args = c
    binding fired args = d
    binding fired args = e
    binding fired args = Up
    binding fired args = Right
    binding fired args = Left
    binding fired args = Down
    binding fired args = Home
    binding fired args = End
    binding fired args = Prior
    binding fired args = Next

    After typing in the 'bind' command, I made the wish window current and
    started typing at the wish window, you see the results above.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Andy Maleh on Sat Nov 6 19:01:31 2021
    Andy Maleh <andy.am@gmail.com> wrote:
    Nevermind, I stand corrected. I just tried binding to '<KeyPress>'
    directly on the text widget in Python TKinter and it worked!

    I guess it is a Ruby-only issue that I cannot bind to standard events
    on the text widget.

    If so, then it is a bug for the Ruby community.

    Well, that just leaves the originally reported issue then.

    Which is not an issue. Deleting all the text tagged with a tag means
    the tag is no longer associated with any text in the widget. If you
    don't retag newly inserted text with that tag, it remains associated
    with no text in the widget.

    And if the tag is not associated with any text in the widget, then the
    bindings on that tag will not fire.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andy Maleh@21:1/5 to Rich on Sat Nov 6 11:28:35 2021
    On Saturday, November 6, 2021 at 12:56:43 PM UTC-4, Rich wrote:
    Andy Maleh wrote:
    Basically, using the tk::text widget, I bind '<KeyPress>' to a tag
    called 'all' covering '1.0' till 'end'. The goal is to track insert
    mark movement via arrow keys (and page-up/page-down/home/end). It
    works until I decide to highlight all text, delete it, and enter new
    text. Afterwards, the binding does not fire any events. But, after
    I enter a number of newlines, sometimes it starts firing again
    (unreliable as a workaround).
    As an alternate, you can bind <KeyPress> on the widget itself and then
    filter for just the keys you are interested in, ignoring the remainder. Binding to the widget itself will mean the event should be unaffected
    by changes within the text widget contents.

    Actually, what you suggest is what I tried first, but I noticed that none of the standard events (e.g. <KeyPress>, <ButtonPress>, etc...) work on the text widget directly. Only when binding to a tag, they work.

    I guess that is another bug to report: binding to standard events like <KeyPress> does not work on text.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andy Maleh@21:1/5 to Andy Maleh on Sat Nov 6 11:32:16 2021
    On Saturday, November 6, 2021 at 2:28:38 PM UTC-4, Andy Maleh wrote:
    On Saturday, November 6, 2021 at 12:56:43 PM UTC-4, Rich wrote:
    Andy Maleh wrote:
    Basically, using the tk::text widget, I bind '<KeyPress>' to a tag
    called 'all' covering '1.0' till 'end'. The goal is to track insert
    mark movement via arrow keys (and page-up/page-down/home/end). It
    works until I decide to highlight all text, delete it, and enter new text. Afterwards, the binding does not fire any events. But, after
    I enter a number of newlines, sometimes it starts firing again (unreliable as a workaround).
    As an alternate, you can bind <KeyPress> on the widget itself and then filter for just the keys you are interested in, ignoring the remainder. Binding to the widget itself will mean the event should be unaffected
    by changes within the text widget contents.
    Actually, what you suggest is what I tried first, but I noticed that none of the standard events (e.g. <KeyPress>, <ButtonPress>, etc...) work on the text widget directly. Only when binding to a tag, they work.

    I guess that is another bug to report: binding to standard events like <KeyPress> does not work on text.

    Nevermind, I stand corrected. I just tried binding to '<KeyPress>' directly on the text widget in Python TKinter and it worked!

    I guess it is a Ruby-only issue that I cannot bind to standard events on the text widget.

    Thank you for the offered workaround.

    Well, that just leaves the originally reported issue then.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andy Maleh@21:1/5 to Andy Maleh on Sat Nov 6 14:26:07 2021
    On Saturday, November 6, 2021 at 5:20:34 PM UTC-4, Andy Maleh wrote:
    On Saturday, November 6, 2021 at 3:01:34 PM UTC-4, Rich wrote:
    Andy Maleh wrote:
    Nevermind, I stand corrected. I just tried binding to '<KeyPress>' directly on the text widget in Python TKinter and it worked!

    I guess it is a Ruby-only issue that I cannot bind to standard events
    on the text widget.
    If so, then it is a bug for the Ruby community.
    Well, that just leaves the originally reported issue then.
    Which is not an issue. Deleting all the text tagged with a tag means
    the tag is no longer associated with any text in the widget. If you
    don't retag newly inserted text with that tag, it remains associated
    with no text in the widget.

    And if the tag is not associated with any text in the widget, then the bindings on that tag will not fire.
    I was able to resolve the Ruby issue by binding events directly on the text widget. It turned out Ruby had a special nicety whereby I do not have to surround the event by '<>'. Ruby automatically does it for me, so I could simply bind to 'KeyPress'
    instead of '<KeyPress>'.

    Thank you again for your suggestion. It worked in Ruby too eventually!

    About the original problem with tag bindings, I actually tried retagging on every text change and that didn't work.

    The reason is because the 'all' tag covering '1.0' to 'end' already covers all text from beginning to end for the past, present ,and future of the text widget content. Retagging does nothing to alleviate the problem.

    Here is a code example written in Python3 to illustrate:

    ```python
    from tkinter import *
    from tkinter import ttk

    root = Tk()

    text = Text(root)
    text.grid()
    text.insert('1.0', "Some giberish\nMore giberish\nNot well spelled giberish")
    text.tag_add('all', '1.0', 'end')
    def print_info(event):
    print('key press')
    print(event)

    def changed(event):
    print('modified')
    text.edit_modified(0)
    text.tag_remove('all', '1.0', 'end')
    text.tag_add('all', '1.0', 'end')

    text.bind('<<Modified>>', changed)
    text.tag_bind('all', '<KeyPress>', print_info)

    text.edit_modified(0)

    root.mainloop()
    ```

    Here is a blockquoted version of the code (hoping it preserves the Python code indentation this time); it auto-retags on every modification to the text widget content:

    from tkinter import *
    from tkinter import ttk

    root = Tk()

    text = Text(root)
    text.grid()
    text.insert('1.0', "Some giberish\nMore giberish\nNot well spelled giberish") text.tag_add('all', '1.0', 'end')
    def print_info(event):
    print('key press')
    print(event)

    def changed(event):
    print('modified')
    text.edit_modified(0)
    text.tag_remove('all', '1.0', 'end')
    text.tag_add('all', '1.0', 'end')
    text.tag_bind('all', '<KeyPress>', print_info)

    text.bind('<<Modified>>', changed)
    text.tag_bind('all', '<KeyPress>', print_info)

    text.edit_modified(0)

    root.mainloop()

    The strangest thing is after you enter a number of newlines after clearing text and entering new text, the tag binding sometimes suddenly starts firing again upon key presses.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andy Maleh@21:1/5 to Rich on Sat Nov 6 14:20:32 2021
    On Saturday, November 6, 2021 at 3:01:34 PM UTC-4, Rich wrote:
    Andy Maleh wrote:
    Nevermind, I stand corrected. I just tried binding to '<KeyPress>' directly on the text widget in Python TKinter and it worked!

    I guess it is a Ruby-only issue that I cannot bind to standard events
    on the text widget.
    If so, then it is a bug for the Ruby community.
    Well, that just leaves the originally reported issue then.
    Which is not an issue. Deleting all the text tagged with a tag means
    the tag is no longer associated with any text in the widget. If you
    don't retag newly inserted text with that tag, it remains associated
    with no text in the widget.

    And if the tag is not associated with any text in the widget, then the bindings on that tag will not fire.

    I was able to resolve the Ruby issue by binding events directly on the text widget. It turned out Ruby had a special nicety whereby I do not have to surround the event by '<>'. Ruby automatically does it for me, so I could simply bind to 'KeyPress'
    instead of '<KeyPress>'.

    Thank you again for your suggestion. It worked in Ruby too eventually!

    About the original problem with tag bindings, I actually tried retagging on every text change and that didn't work.

    The reason is because the 'all' tag covering '1.0' to 'end' already covers all text from beginning to end for the past, present ,and future of the text widget content. Retagging does nothing to alleviate the problem.

    Here is a code example written in Python3 to illustrate:

    ```python
    from tkinter import *
    from tkinter import ttk

    root = Tk()

    text = Text(root)
    text.grid()
    text.insert('1.0', "Some giberish\nMore giberish\nNot well spelled giberish") text.tag_add('all', '1.0', 'end')
    def print_info(event):
    print('key press')
    print(event)

    def changed(event):
    print('modified')
    text.edit_modified(0)
    text.tag_remove('all', '1.0', 'end')
    text.tag_add('all', '1.0', 'end')

    text.bind('<<Modified>>', changed)
    text.tag_bind('all', '<KeyPress>', print_info)

    text.edit_modified(0)

    root.mainloop()
    ```

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Andy Maleh on Sun Nov 7 03:04:56 2021
    Andy Maleh <andy.am@gmail.com> wrote:
    On Saturday, November 6, 2021 at 3:01:34 PM UTC-4, Rich wrote:
    Andy Maleh wrote:
    Nevermind, I stand corrected. I just tried binding to '<KeyPress>'
    directly on the text widget in Python TKinter and it worked!

    I guess it is a Ruby-only issue that I cannot bind to standard events
    on the text widget.
    If so, then it is a bug for the Ruby community.
    Well, that just leaves the originally reported issue then.
    Which is not an issue. Deleting all the text tagged with a tag means
    the tag is no longer associated with any text in the widget. If you
    don't retag newly inserted text with that tag, it remains associated
    with no text in the widget.

    And if the tag is not associated with any text in the widget, then the
    bindings on that tag will not fire.

    I was able to resolve the Ruby issue by binding events directly on
    the text widget. It turned out Ruby had a special nicety whereby I
    do not have to surround the event by '<>'. Ruby automatically does
    it for me, so I could simply bind to 'KeyPress' instead of
    '<KeyPress>'.

    Ah, that would make a difference then.


    About the original problem with tag bindings, I actually tried
    retagging on every text change and that didn't work.

    The reason is because the 'all' tag covering '1.0' to 'end' already
    covers all text from beginning to end for the past, present ,and
    future of the text widget content. Retagging does nothing to
    alleviate the problem.

    Nope. Line numbers added below manually:

    01 $ rlwrap wish
    02 % text .t
    03 .t
    04 % pack .t
    05 % .t insert end "The quick brown fox jumped over the lazy dog\n"
    06 % .t insert end "Mary had a little lamb, it's fleece was white as snow\n"
    07 % .t tag add all 0.0 end
    08 % .t tag ranges all
    09 1.0 4.0
    10 % .t delete 0.0 end
    11 % .t tag ranges all
    12 % .t insert end "The quick brown fox jumped over the lazy dog\n"
    13 % .t insert end "Mary had a little lamb, it's fleece was white as snow\n"
    14 % .t tag ranges all
    15 %

    At line 7, a tag named all is added covering the entirety of the text.
    The 'tag ranges' command shows it is attached to the text in the
    widget.

    Line 10 deletes all the text.

    Line 11 shows that the 'all' tag is no longer associated to any text
    within the widget.

    Lines 12 and 13 reinsert the text (I just reused lines 5 and 6).

    Line 14 shows that the all tag is unchanged, it is associated with no
    text within the widget. To have a tag binding fire that tag must be
    associated with some text in the widget. A tag with no text associated
    to it will not fire its binding scripts.

    Here is a code example written in Python3 to illustrate:

    ```python
    from tkinter import *
    from tkinter import ttk

    root = Tk()

    text = Text(root)
    text.grid()
    text.insert('1.0', "Some giberish\nMore giberish\nNot well spelled giberish") text.tag_add('all', '1.0', 'end')
    def print_info(event):
    print('key press')
    print(event)

    def changed(event):
    print('modified')
    text.edit_modified(0)
    text.tag_remove('all', '1.0', 'end')
    text.tag_add('all', '1.0', 'end')

    text.bind('<<Modified>>', changed)
    text.tag_bind('all', '<KeyPress>', print_info)

    text.edit_modified(0)

    root.mainloop()
    ```

    And..., if you were to delete all of the text in the widget (by say
    'selecting all' and pressing "delete", you will end up with the all tag
    not associated with any text. Subsequent typing of text after deleting
    on the keyboard will insert untagged text, which will not be associated
    to the "all" tag.

    Here's another illustration:

    $ rlwrap wish
    % text .t
    .t
    % pack .t
    % .t insert end "The quick brown fox jumped over the lazy dog\n"
    % .t insert end "Mary had a little lamb, it's fleece was white as snow\n"
    % .t tag add all 0.0 end
    % .t tag configure all -background yellow
    % # now type something at the end, it is in yellow
    % .t get 0.0 end
    The quick brown fox jumped over the lazy dog
    Mary had a little lamb, it's fleece was white as snow
    this is some new text

    % # now delete the text in the widget using select all and delete key
    % .t get 0.0 end


    % .t tag ranges all
    % # now type new text - it will not have a yellow background
    % .t get 0.0 end
    this is even newer text

    % .t tag ranges all
    %

    The 'yellow' background just makes what is, or is not, tagged very
    visible in the text widget.

    Deleting everything by selecting all (control+/) and deleting (Delete)
    results in an all tag with no ranges. And subsequent typing does not
    enter text with a yellow background. That newly typed text is
    untagged, because the select all plus delete by the keyboard
    disassociated the tag with any text in the widget.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Andy Maleh on Sun Nov 7 03:15:06 2021
    Andy Maleh <andy.am@gmail.com> wrote:
    Here is a blockquoted version of the code (hoping it preserves the
    Python code indentation this time); it auto-retags on every
    modification to the text widget content:

    from tkinter import *
    from tkinter import ttk

    root = Tk()

    text = Text(root)
    text.grid()
    text.insert('1.0', "Some giberish\nMore giberish\nNot well spelled giberish")
    text.tag_add('all', '1.0', 'end')
    def print_info(event):
    print('key press')
    print(event)

    def changed(event):
    print('modified')
    text.edit_modified(0)
    text.tag_remove('all', '1.0', 'end')
    text.tag_add('all', '1.0', 'end')
    text.tag_bind('all', '<KeyPress>', print_info)

    text.bind('<<Modified>>', changed)
    text.tag_bind('all', '<KeyPress>', print_info)

    text.edit_modified(0)

    root.mainloop()

    The strangest thing is after you enter a number of newlines after
    clearing text and entering new text, the tag binding sometimes
    suddenly starts firing again upon key presses.

    I made two one tiny changes to your Python while rewriting it as plain
    Tcl. One, the tag includes a yellow highlight to "see" where it
    exists. Two, instead of rebinding the all tag to the <KeyPress> event
    on every modification, I bound it once at the outer level. I.e., I
    changed it to this:

    def changed(event):
    print('modified')
    text.edit_modified(0)
    text.tag_remove('all', '1.0', 'end')
    text.tag_add('all', '1.0', 'end')

    text.tag_bind('all', '<KeyPress>', print_info)
    text.bind('<<Modified>>', changed)
    text.tag_bind('all', '<KeyPress>', print_info)

    And with Tcl, with that change, your script works perfectly. The text
    stay's tagged, even if I delete everything.

    So, try binding the tag once, at outer level, and see if that works for
    you.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andy Maleh@21:1/5 to Rich on Sun Nov 7 10:40:05 2021
    On Saturday, November 6, 2021 at 11:15:09 PM UTC-4, Rich wrote:
    Andy Maleh wrote:
    Here is a blockquoted version of the code (hoping it preserves the
    Python code indentation this time); it auto-retags on every
    modification to the text widget content:

    from tkinter import *
    from tkinter import ttk

    root = Tk()

    text = Text(root)
    text.grid()
    text.insert('1.0', "Some giberish\nMore giberish\nNot well spelled giberish")
    text.tag_add('all', '1.0', 'end')
    def print_info(event):
    print('key press')
    print(event)

    def changed(event):
    print('modified')
    text.edit_modified(0)
    text.tag_remove('all', '1.0', 'end')
    text.tag_add('all', '1.0', 'end')
    text.tag_bind('all', '<KeyPress>', print_info)

    text.bind('<<Modified>>', changed)
    text.tag_bind('all', '<KeyPress>', print_info)

    text.edit_modified(0)

    root.mainloop()

    The strangest thing is after you enter a number of newlines after
    clearing text and entering new text, the tag binding sometimes
    suddenly starts firing again upon key presses.
    I made two one tiny changes to your Python while rewriting it as plain
    Tcl. One, the tag includes a yellow highlight to "see" where it
    exists. Two, instead of rebinding the all tag to the <KeyPress> event
    on every modification, I bound it once at the outer level. I.e., I
    changed it to this:
    def changed(event):
    print('modified')
    text.edit_modified(0)
    text.tag_remove('all', '1.0', 'end')
    text.tag_add('all', '1.0', 'end')

    text.tag_bind('all', '<KeyPress>', print_info)
    text.bind('<<Modified>>', changed)
    text.tag_bind('all', '<KeyPress>', print_info)
    And with Tcl, with that change, your script works perfectly. The text
    stay's tagged, even if I delete everything.

    So, try binding the tag once, at outer level, and see if that works for
    you.

    Wow! I would look forward to having a version that works.

    Question: the code you shared is in Python (and it also repeats the tag binding twice at the outer level, once before binding <<Modified>> and once afterwards). It actually resembles my original version that had the problem (I was originally only tag
    binding once; I only tried retagging and rebinding in the modified event handler as a failed workaround)

    Do you have the Tcl code that worked for you? Even if I'm more of a Rubyist (Python is not even my language, I only used it to illustrate that the problem is not constrainted to the Ruby bindings), I could take a stab at understanding the Tcl code.

    Thank you,

    Andy

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Andy Maleh on Sun Nov 7 19:33:59 2021
    Andy Maleh <andy.am@gmail.com> wrote:
    On Saturday, November 6, 2021 at 11:15:09 PM UTC-4, Rich wrote:
    So, try binding the tag once, at outer level, and see if that works
    for you.

    Wow! I would look forward to having a version that works.

    Question: the code you shared is in Python (and it also repeats the
    tag binding twice at the outer level, once before binding
    <<Modified>> and once afterwards).

    What I tried to share was a snippet of your python, with an attempt to
    show the change I made. It is possible my editing of the python did
    not go as planned.

    Do you have the Tcl code that worked for you?

    No, as I just typed it into a REPL. It is a pretty straightforward
    translation from your python you posted.

    Here is a working variant, recreated (note that I don't actually use
    the "args" on changed, so it could have been defined as
    "proc changed {} {"):

    text .t
    pack .t
    .t insert end "Some giberish\nMore giberish\nNot well spelled giberish"
    .t tag add all 0.0 end
    .t tag configure all -background yellow

    proc key {args} {
    puts stderr "keypress args='$args'"
    }

    proc changed {args} {
    puts stderr "modified"
    .t edit modified 0
    .t tag add all 0.0 end
    }

    bind .t <<Modified>> [list changed]
    .t tag bind all <KeyPress> [list key %K]
    .t edit modified 0


    Even if I'm more of a Rubyist (Python is not even my language, I only
    used it to illustrate that the problem is not constrainted to the
    Ruby bindings), I could take a stab at understanding the Tcl code.

    The above snippet is Tcl, that does what I believe you are expecting.
    However, binding to the text to grab keystrokes will likely be superior
    than trying to use a <<Modified>> event to 'retag' the entire text.
    Performance of the bind to the text itself will likely be better,
    possibly much better if the text widget contains a large amount of
    text.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andy Maleh@21:1/5 to Andy Maleh on Tue Nov 9 05:58:01 2021
    On Tuesday, November 9, 2021 at 8:50:08 AM UTC-5, Andy Maleh wrote:
    On Sunday, November 7, 2021 at 2:34:02 PM UTC-5, Rich wrote:
    Andy Maleh wrote:
    On Saturday, November 6, 2021 at 11:15:09 PM UTC-4, Rich wrote:
    So, try binding the tag once, at outer level, and see if that works
    for you.

    Wow! I would look forward to having a version that works.

    Question: the code you shared is in Python (and it also repeats the
    tag binding twice at the outer level, once before binding
    <<Modified>> and once afterwards).
    What I tried to share was a snippet of your python, with an attempt to show the change I made. It is possible my editing of the python did
    not go as planned.
    Do you have the Tcl code that worked for you?
    No, as I just typed it into a REPL. It is a pretty straightforward translation from your python you posted.

    Here is a working variant, recreated (note that I don't actually use
    the "args" on changed, so it could have been defined as
    "proc changed {} {"):

    text .t
    pack .t
    .t insert end "Some giberish\nMore giberish\nNot well spelled giberish"
    .t tag add all 0.0 end
    .t tag configure all -background yellow
    proc key {args} {
    puts stderr "keypress args='$args'"
    }

    proc changed {args} {
    puts stderr "modified"
    .t edit modified 0
    .t tag add all 0.0 end
    }
    bind .t <<Modified>> [list changed]
    .t tag bind all <KeyPress> [list key %K]
    .t edit modified 0
    Even if I'm more of a Rubyist (Python is not even my language, I only used it to illustrate that the problem is not constrainted to the
    Ruby bindings), I could take a stab at understanding the Tcl code.
    The above snippet is Tcl, that does what I believe you are expecting. However, binding to the text to grab keystrokes will likely be superior than trying to use a <<Modified>> event to 'retag' the entire text. Performance of the bind to the text itself will likely be better,
    possibly much better if the text widget contains a large amount of
    text.
    Hi,

    Thank you for providing the Tcl example that worked for you.

    It does not work for me when I convert to Ruby or Python.

    Here is the Ruby counterpart (which I adjusted away from Ruby idioms to make it look closer to the Tcl code):

    require 'tk'

    root = Tk::Root.new

    text = Tk::Text.new(root)
    text.pack
    text.insert 'end', "Some giberish repeated many times\n"*20 text.tag_add('all', '0.0', 'end')
    text.tag_configure('all', 'background', 'yellow')

    text.bind('<Modified>') { |event|
    print "modified\n"
    text.modified = false
    text.tag_add('all', '0.0', 'end')
    }
    text.tag_bind('all', 'KeyPress') { |event|
    print "key press: #{event.inspect}\n"
    }
    text.modified = false

    root.mainloop

    One thing I noticed is you used 0.0 for the start index instead of 1.0. According to the Tcl/Tk docs (https://tkdocs.com/tutorial/text.html), I believe 1.0 is the correct beginning since lines are 1-based even though characters are 0-based, but I
    digress.

    I do see the first line colored with a yellow background after clearing out all the text (e.g. CMD+A & DELETE), but still it does not fire binding changes upon key presses after adding new text in the yellow area.

    I just tried your Tcl code using tkcon, and I still got the same problem. I get printouts when navigating by arrow keys before clearing text. After clearing, if I enter a few characters on the first line and then navigate with arrow keys, nothing prints.
    I have to enter a few newlines before printouts happen again (it is a bit random when they would happen again)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andy Maleh@21:1/5 to Rich on Tue Nov 9 05:50:06 2021
    On Sunday, November 7, 2021 at 2:34:02 PM UTC-5, Rich wrote:
    Andy Maleh wrote:
    On Saturday, November 6, 2021 at 11:15:09 PM UTC-4, Rich wrote:
    So, try binding the tag once, at outer level, and see if that works
    for you.

    Wow! I would look forward to having a version that works.

    Question: the code you shared is in Python (and it also repeats the
    tag binding twice at the outer level, once before binding
    <<Modified>> and once afterwards).
    What I tried to share was a snippet of your python, with an attempt to
    show the change I made. It is possible my editing of the python did
    not go as planned.
    Do you have the Tcl code that worked for you?
    No, as I just typed it into a REPL. It is a pretty straightforward translation from your python you posted.

    Here is a working variant, recreated (note that I don't actually use
    the "args" on changed, so it could have been defined as
    "proc changed {} {"):

    text .t
    pack .t
    .t insert end "Some giberish\nMore giberish\nNot well spelled giberish"
    .t tag add all 0.0 end
    .t tag configure all -background yellow
    proc key {args} {
    puts stderr "keypress args='$args'"
    }

    proc changed {args} {
    puts stderr "modified"
    .t edit modified 0
    .t tag add all 0.0 end
    }
    bind .t <<Modified>> [list changed]
    .t tag bind all <KeyPress> [list key %K]
    .t edit modified 0
    Even if I'm more of a Rubyist (Python is not even my language, I only
    used it to illustrate that the problem is not constrainted to the
    Ruby bindings), I could take a stab at understanding the Tcl code.
    The above snippet is Tcl, that does what I believe you are expecting. However, binding to the text to grab keystrokes will likely be superior
    than trying to use a <<Modified>> event to 'retag' the entire text. Performance of the bind to the text itself will likely be better,
    possibly much better if the text widget contains a large amount of
    text.

    Hi,

    Thank you for providing the Tcl example that worked for you.

    It does not work for me when I convert to Ruby or Python.

    Here is the Ruby counterpart (which I adjusted away from Ruby idioms to make it look closer to the Tcl code):

    require 'tk'

    root = Tk::Root.new

    text = Tk::Text.new(root)
    text.pack
    text.insert 'end', "Some giberish repeated many times\n"*20
    text.tag_add('all', '0.0', 'end')
    text.tag_configure('all', 'background', 'yellow')

    text.bind('<Modified>') { |event|
    print "modified\n"
    text.modified = false
    text.tag_add('all', '0.0', 'end')
    }
    text.tag_bind('all', 'KeyPress') { |event|
    print "key press: #{event.inspect}\n"
    }
    text.modified = false

    root.mainloop

    One thing I noticed is you used 0.0 for the start index instead of 1.0. According to the Tcl/Tk docs (https://tkdocs.com/tutorial/text.html), I believe 1.0 is the correct beginning since lines are 1-based even though characters are 0-based, but I digress.

    I do see the first line colored with a yellow background after clearing out all the text (e.g. CMD+A & DELETE), but still it does not fire binding changes upon key presses after adding new text in the yellow area.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andy Maleh@21:1/5 to Rich on Tue Nov 9 07:07:21 2021
    On Tuesday, November 9, 2021 at 9:54:57 AM UTC-5, Rich wrote:
    Andy Maleh wrote:
    On Tuesday, November 9, 2021 at 8:50:08 AM UTC-5, Andy Maleh wrote:
    On Sunday, November 7, 2021 at 2:34:02 PM UTC-5, Rich wrote:
    Here is a working variant, recreated (note that I don't actually use
    the "args" on changed, so it could have been defined as
    "proc changed {} {"):

    text .t
    pack .t
    .t insert end "Some giberish\nMore giberish\nNot well spelled giberish" >> > .t tag add all 0.0 end
    .t tag configure all -background yellow
    proc key {args} {
    puts stderr "keypress args='$args'"
    }

    proc changed {args} {
    puts stderr "modified"
    .t edit modified 0
    .t tag add all 0.0 end
    }
    bind .t <<Modified>> [list changed]
    .t tag bind all <KeyPress> [list key %K]
    .t edit modified 0
    Even if I'm more of a Rubyist (Python is not even my language, I only >> > > used it to illustrate that the problem is not constrainted to the
    Ruby bindings), I could take a stab at understanding the Tcl code.
    The above snippet is Tcl, that does what I believe you are expecting.
    However, binding to the text to grab keystrokes will likely be superior >> > than trying to use a <<Modified>> event to 'retag' the entire text.
    Performance of the bind to the text itself will likely be better,
    possibly much better if the text widget contains a large amount of
    text.
    Hi,

    Thank you for providing the Tcl example that worked for you.

    It does not work for me when I convert to Ruby or Python.

    Here is the Ruby counterpart (which I adjusted away from Ruby idioms
    to make it look closer to the Tcl code):

    require 'tk'

    root = Tk::Root.new

    text = Tk::Text.new(root)
    text.pack
    text.insert 'end', "Some giberish repeated many times\n"*20
    text.tag_add('all', '0.0', 'end')
    text.tag_configure('all', 'background', 'yellow')

    text.bind('<Modified>') { |event|
    In Tcl, the binding here is <<Modified>> (the double brackets are meaningful). Does Ruby auto-insert a pair of < >'s?
    print "modified\n"
    text.modified = false
    text.tag_add('all', '0.0', 'end')
    }
    text.tag_bind('all', 'KeyPress') { |event|
    print "key press: #{event.inspect}\n"
    }
    text.modified = false

    root.mainloop

    One thing I noticed is you used 0.0 for the start index instead of
    1.0. According to the Tcl/Tk docs
    (https://tkdocs.com/tutorial/text.html), I believe 1.0 is the
    correct beginning since lines are 1-based even though characters are
    0-based, but I digress.
    Even so, 0.0 is before 1.0 so also means "first line".
    I do see the first line colored with a yellow background after
    clearing out all the text (e.g. CMD+A & DELETE), but still it does
    not fire binding changes upon key presses after adding new text in
    the yellow area.

    I just tried your Tcl code using tkcon, and I still got the same
    problem. I get printouts when navigating by arrow keys before
    clearing text. After clearing, if I enter a few characters on the
    first line and then navigate with arrow keys, nothing prints. I have
    to enter a few newlines before printouts happen again (it is a bit
    random when they would happen again)
    Trying your specific steps above, I get the same result. If I
    Control+/ and then Delete, typing produces no keypresses until after I
    enter a first (or occasionally more) newline(s). I had not seen this
    before because I did not know your specific steps above that seem to
    trigger it.

    So some kind of weird binding bug exists here.

    "In Tcl, the binding here is <<Modified>> (the double brackets are
    meaningful). Does Ruby auto-insert a pair of < >'s?"

    Yes, Ruby does auto-insert a pair of < >, so "<Modified>" is what is required in Ruby for that binding to work.

    Thank you for testing and confirming.

    Best regards,

    Andy

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Andy Maleh on Tue Nov 9 14:54:53 2021
    Andy Maleh <andy.am@gmail.com> wrote:
    On Tuesday, November 9, 2021 at 8:50:08 AM UTC-5, Andy Maleh wrote:
    On Sunday, November 7, 2021 at 2:34:02 PM UTC-5, Rich wrote:
    Here is a working variant, recreated (note that I don't actually use
    the "args" on changed, so it could have been defined as
    "proc changed {} {"):

    text .t
    pack .t
    .t insert end "Some giberish\nMore giberish\nNot well spelled giberish"
    .t tag add all 0.0 end
    .t tag configure all -background yellow
    proc key {args} {
    puts stderr "keypress args='$args'"
    }

    proc changed {args} {
    puts stderr "modified"
    .t edit modified 0
    .t tag add all 0.0 end
    }
    bind .t <<Modified>> [list changed]
    .t tag bind all <KeyPress> [list key %K]
    .t edit modified 0
    Even if I'm more of a Rubyist (Python is not even my language, I only
    used it to illustrate that the problem is not constrainted to the
    Ruby bindings), I could take a stab at understanding the Tcl code.
    The above snippet is Tcl, that does what I believe you are expecting.
    However, binding to the text to grab keystrokes will likely be superior
    than trying to use a <<Modified>> event to 'retag' the entire text.
    Performance of the bind to the text itself will likely be better,
    possibly much better if the text widget contains a large amount of
    text.
    Hi,

    Thank you for providing the Tcl example that worked for you.

    It does not work for me when I convert to Ruby or Python.

    Here is the Ruby counterpart (which I adjusted away from Ruby idioms
    to make it look closer to the Tcl code):

    require 'tk'

    root = Tk::Root.new

    text = Tk::Text.new(root)
    text.pack
    text.insert 'end', "Some giberish repeated many times\n"*20
    text.tag_add('all', '0.0', 'end')
    text.tag_configure('all', 'background', 'yellow')

    text.bind('<Modified>') { |event|

    In Tcl, the binding here is <<Modified>> (the double brackets are
    meaningful). Does Ruby auto-insert a pair of < >'s?

    print "modified\n"
    text.modified = false
    text.tag_add('all', '0.0', 'end')
    }
    text.tag_bind('all', 'KeyPress') { |event|
    print "key press: #{event.inspect}\n"
    }
    text.modified = false

    root.mainloop

    One thing I noticed is you used 0.0 for the start index instead of
    1.0. According to the Tcl/Tk docs
    (https://tkdocs.com/tutorial/text.html), I believe 1.0 is the
    correct beginning since lines are 1-based even though characters are
    0-based, but I digress.

    Even so, 0.0 is before 1.0 so also means "first line".

    I do see the first line colored with a yellow background after
    clearing out all the text (e.g. CMD+A & DELETE), but still it does
    not fire binding changes upon key presses after adding new text in
    the yellow area.

    I just tried your Tcl code using tkcon, and I still got the same
    problem. I get printouts when navigating by arrow keys before
    clearing text. After clearing, if I enter a few characters on the
    first line and then navigate with arrow keys, nothing prints. I have
    to enter a few newlines before printouts happen again (it is a bit
    random when they would happen again)

    Trying your specific steps above, I get the same result. If I
    Control+/ and then Delete, typing produces no keypresses until after I
    enter a first (or occasionally more) newline(s). I had not seen this
    before because I did not know your specific steps above that seem to
    trigger it.

    So some kind of weird binding bug exists here.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Francois Vogel@21:1/5 to All on Fri Nov 12 18:06:20 2021
    Le 09/11/2021 à 15:54, Rich a écrit :
    So some kind of weird binding bug exists here.

    Follow-up to:

    https://core.tcl-lang.org/tk/tktview/631a0b2d95

    Regards,
    Francois

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Francois Vogel@21:1/5 to All on Fri Nov 12 22:40:57 2021
    Le 12/11/2021 à 18:06, Francois Vogel a écrit :
    Le 09/11/2021 à 15:54, Rich a écrit :
    So some kind of weird binding bug exists here.

    Follow-up to:

        https://core.tcl-lang.org/tk/tktview/631a0b2d95

    I have dropped my analysis in that ticket. In a nutshsell: there is no
    bug, it works as designed.

    The man page however could (and probably should) explain all this much
    better however (any suggestions for a better text, someone?)

    Regards,
    Francois

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mike Griffiths@21:1/5 to Francois Vogel on Fri Nov 12 15:54:32 2021
    On Friday, 12 November 2021 at 21:41:01 UTC, Francois Vogel wrote:
    Le 12/11/2021 à 18:06, Francois Vogel a écrit :
    Le 09/11/2021 à 15:54, Rich a écrit :
    So some kind of weird binding bug exists here.

    Follow-up to:

    https://core.tcl-lang.org/tk/tktview/631a0b2d95
    I have dropped my analysis in that ticket. In a nutshsell: there is no
    bug, it works as designed.

    The man page however could (and probably should) explain all this much better however (any suggestions for a better text, someone?)

    Regards,
    Francois
    While I agree that the manpage *could* be interpreted that way, I would still consider it a bug, or at the very least a feature so useless it should be classed the same way; I can't see any benefit to having keyboard-related bindings on a text-based
    widget which only respond when the mouse pointer is located inside the widget. And if desired, that's a behaviour that's really easy to code with winfo containing/winfopointerxy anyway.

    It's also worth noting that, while "current" may not be updated when the mouse is outside the widget, it still exists (with [$widget index current] always returning 1.0) so technically from how the manpage is worded I don't think there's anything to say
    the bindings shouldn't still fire.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Francois Vogel@21:1/5 to That on Sat Nov 13 16:53:06 2021
    Le 13/11/2021 à 00:54, Mike Griffiths a écrit :
    While I agree that the manpage *could* be interpreted that way, I would still consider it a bug

    The man page AND the code are consistent. The intent is clear in the code.

    That said, improvement is possible. See the ticket for a proposal.

    It's also worth noting that, while "current" may not be updated when the mouse is outside the widget, it still exists (with [$widget index current] always returning 1.0) so technically from how the manpage is worded I don't think there's anything to
    say the bindings shouldn't still fire.

    In my implementation I decided that, for key events, 'insert' is a
    better mark to consider than 'current'.

    Regards,
    Francois

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