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

Dear wise Perl guys,

I have an Tk::Entry widget with both -textvariable and -validatecommand options defined.
I know, that this is risky, but it works fine as long as I don't assign to the variable used as the textvariable inside my validate command sub itself.
If I do so, the validate option is obviously turned to 'none' when I assign to the textvariable.

Thanks & Regards,
petro4213

  • Comment on Tk::Entry widget with textvariable and validatecommand

Replies are listed 'Best First'.
Re: Tk::Entry widget with textvariable and validatecommand
by kcott (Archbishop) on Nov 06, 2017 at 16:16 UTC

    G'day petro4213,

    Welcome to the Monastery.

    Without any code, it's unclear what you're actually attempting and how it's not doing what you want. Please read "How do I post a question effectively?". Then provide a "SSCCE": keep it short; do not include cosmetic elements (e.g. colours, fonts, etc.); include a small piece of ASCII art to describe your GUI where appropriate (although, there's probably no need here).

    Read the documentation for Tk::Entry, especially the VALIDATION section.

    — Ken

      Hi Ken

      thanks for replying. As my question seemed so general and simple to me, I thought I could go without any code. Of course I read the docu first, but it only says that using textvariable and validatecommand "can be dangerous to mix", which doesn't help much. Anyway, let's try with this code snippet:

      use Tk; my $mw = MainWindow->new(); my $textvar = 1; $mw->Entry(-textvariable => \$textvar, -validatecommand => sub { my ($new,$changed,$old,$ix,$type) = @_; return 1 if (!defined($changed)); return 1 if ($new eq "") or ($type<0); $textvar = $new & 3; # use only 2 low bits print "masked out entry value\n"; return 1; }, -validate => 'key')->pack(); MainLoop;

      When started, a window with an Entry widget appears, with value 1 displayed. If you first enter e.g. the value 7, it will print the message and change the value to 3 (because 7 & 3 = 3). Any further entries will pass unchanged and no message will be printed anymore.

      Therefore I assume, that the validate option was set to 'none'. The docu says, that this happens, when some error occurred (maybe setting the textvar from the validatecommand callback is such an error?).

      Does this clarify my problem? Do you have any advice, better than my ugly workaround of using an "after" call

      Thanks and kind regards
      petro4213

Re: Tk::Entry widget with textvariable and validatecommand
by beech (Parson) on Nov 07, 2017 at 03:34 UTC

    Hi

    Is it forbidden to assign to the textvariable inside the validate command?

    Sounds true :) maybe

    Is there a way to get this done other than not using the validatecommand and binding some events (like <Return> key or focus out to some subroutine).

    Um, whats wrong with using bindings or ->after?

    See "phone number entry" in "Tk/demos/widget_lib/entry3.pl", sub entry3_validate_phone uses the same strategy you used, but uses ->afterIdle instead of ->after

    Heh

    #!/usr/bin/perl -- use strict; use warnings; use Tk; my $mw = MainWindow->new(); my $textvar = 1; my $e = $mw->Entry( -textvariable => \$textvar, -validate => 'key', ); $e->configure( -validatecommand => [ \&myValidate, $e ], ); $e->pack(); MainLoop; sub _configurevalidate_key { $Tk::widget->configure( -validate, 'key' ); } sub myValidate { my( $entry, $new, $changed, $old, $ix, $type ) = @_; #~ $entry->afterIdle( [ \&_configurevalidate_key, $e ] ); $entry->afterIdle( \&_configurevalidate_key ); return 1 if( !defined( $changed ) ); return 1 if( $new eq "" ) or( $type < 0 ); $textvar = $new & 3; # use only 2 low bits print "masked out entry value\n"; return 1; } __END__

      Hi beech

      Thanks for the reply. Generally there's nothing wrong with using bindings or after, but to me they feel like more or less ugly or cumbersome workarounds here. Usually Tk widgets have everything built in, what is required to use them. I thought that correcting an erroneous entry could be a common use case of an Entry widget, but maybe it's not.

      Anyway thanks for pointing me to afterIdle; might be a bit more robust than using after with some random timing value.

      Cheers,
      petro4213

Re: Tk::Entry widget with textvariable and validatecommand
by petro4213 (Acolyte) on Nov 06, 2017 at 15:02 UTC

    I found one (ugly) way to do it:

    Instead of directly changing the textvariable contents, I delegate this to a slightly later point using an "after" call. So instead of the line

    $textvar = $new & 3;
    I use this code line:
    $mw->after(10, sub { $textvar = $new & 3 });

    Btw.: Doing the change of the textvariable contents in the invalidcommand callback also turns the validate option to 'none'.

Re: Tk::Entry widget with textvariable and validatecommand
by chrstphrchvz (Scribe) on Apr 22, 2019 at 15:42 UTC

    See RT #102648: doing so currently causes a double free to occur. (Not sure whether this is expected behavior, i.e. “you have been warned”.)