Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I need to read the content of a Tk Text Widget every time its content changes. The problem is that focus is always on the text widget and no key is pressed (text is input through speech recognition module with chunks of sentences added every time). At the moment my solution is quite simple: every x ms I read the content of the widget (sampling) and see if something has changed. However, I am not satisfied by this solution. The reason is that a) I guess is computationally not optimized b) it can happen that the sampling breaks the chunkes of texts added into the text widget.

This is what I have now

use warnings; use strict; use Tk; my $mw = MainWindow->new(); my $tx = $mw->Text()->pack(); $mw->repeat(1000, \&readTextWidget); my $CursorPosition="1.0";#starting index in Tk Text MainLoop; sub readTextWidget{ my @Text=$tx->dump($CursorPosition,'end'); my $TextChunk = $Text[1]; $CursorPosition= $Text[5]; if ($text ne "current"){#skip Tk:Text indicators my @words = split / /, $TextChunk ; foreach my $word (@words) { print "$word\n"; } } }

Any better idea to avoid the repeat function and call the sub readTextWidget when a change in the Tk widget occurs?

Replies are listed 'Best First'.
Re: read Tk Text Widget when content changes
by Discipulus (Canon) on Aug 07, 2017 at 11:28 UTC
    Hello Anonymous Monk,

    you can profit the <<Modified>> virtual event (see it here), for a first-time-only modification, like in,

    use strict; use warnings; use Tk; my $mw = new MainWindow; my $text = $mw->Text(qw/-width 40 -height 10/)->pack; my $current_color = "black"; $text->configure(-insertbackground => $current_color); $text->configure(-cursor => "arrow"); my $button = $mw->Button(-text => "Quit", -command => sub { exit })->p +ack; $text->bind('<<Modified>>', sub{warn "text changed\n"} ); MainLoop;

    And you c an also play resetting $text->editModified to zero but follow what our wise zentara said about avoinding an infinite loop: Re: Using Tk::Text and '<<Modified>>'

    See also Onchange-like event handler for Tk text widget

    L*

    PS you can have a better control, but still not optimale with:

    my $len; .. $text->bind('<<Modified>>', sub{ if ($len != length $text->Contents ){ $len = length $text->Contents; warn "text changed ($len)\n"; $text->editModified(0) } } );

    or better (but breaks on backspaces..)

    $text->bind('<<Modified>>', sub{ if ($len ne $text->Contents ){ $len = $text->Contents; warn "text changed\n"; $text->editModified(0) } } );

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      Thank you very much!

      After playing a bit with the tips and examples provided I came up with this solution which seems to suit perfectly

      use warnings; use strict; use Tk; my $mw = MainWindow->new(); my $tx = $mw->Text()->pack(); $tx->bind( '<<Modified>>' => \&readTextWidget); my $CursorPosition="1.0"; MainLoop; sub readTextWidget{ if ($tx->editModified()) { my @Text=$tx->dump($CursorPosition,'end'); my $TextChunk = $Text[1]; $CursorPosition= $Text[5]; my @words = split / /, $TextChunk ;#very basic tokenizer for t +he moment foreach my $word (@words) { print "$word\n"; } $tx->editModified(0); } }
Re: read Tk Text Widget when content changes
by zentara (Cardinal) on Aug 07, 2017 at 13:17 UTC
    Hi again, I Tk is a very simple and easy to use toolkit, but Gtk2 is more powerful but harder to use. Just for your information, here is how it's done in Gtk2.
    #!/usr/bin/perl -w use strict; use Gtk2 -init; my $window = Gtk2::Window->new; $window->signal_connect (destroy => sub {Gtk2->main_quit}); $window->set_default_size (400, 300); my $textview = Gtk2::TextView->new; $window->add ($textview); my $n; $textview->get_buffer->signal_connect ( changed => sub { print "changed! ".(++$n)."\n"}); $window->show_all; Gtk2->main;

    I'm not really a human, but I play one on earth. ..... an animated JAPH
Re: read Tk Text Widget when content changes
by zentara (Cardinal) on Aug 07, 2017 at 12:00 UTC
    Hi, Discipulus pretty much covered the bases for you, but once I have resorted to a less than ideal solution of taking the md5sum of the text, storing it, and checking for differences.

    I'm not really a human, but I play one on earth. ..... an animated JAPH