Win32 - Perl/Tk - Eingabe filtern mit validate im Entry-Widget
Win32 - Perl/Tk - Eingabe filtern mit validate im Entry-Widget
am 27.04.2007 17:27:04 von Robert Berghaus
Hallo
Ich versuche mich zur Zeit an einem Dialog mit Eingabefeld und=20
Listbox. Das Format fürs Eingabefeld ist: 1-2 Ziffern, beliebige=20
Anzahl Leerzeichen und Text
Der Text darf nur Großbuchstaben enthalten und keine Umlaute.=20
Jetzt will ich dem Anwender nicht zumuten, nur Großbuchstaben=20
einzugeben, sondern diese selber konvertieren.
Das Beispiel entry3 aus Widget zeigt ja ganz schön, wie es gehen kann.
$e3 =3D $lf3->Entry(
-validate =3D> 'key',
-invalidcommand =3D> sub {$TOP->bell},
-textvariable =3D> \$e3_var,
);
$e3->configure(
-validatecommand =3D> [\&entry3_validate_phone, $e3, \%l2n],
);
$e3->pack(qw/-fill x -expand 1 -padx 1m -pady 1m/);
In der sub entry3_validate_phone habe ich dann gefunden, wie das=20
Widget nach Änderung der Eingabe durchs Programm wieder zum=20
Mitmachen aufgefordert werden kann (nach jeder Änderung durchs=20
Programm scheint das Widget beleidigt das Prüfen dranzugeben ;-) )
my $val =3D $w->cget(-validate);
$w->afterIdle(sub {
$w->configure(
-validate =3D> $val,
-invalidcommand =3D> sub {$w->bell},
);
});
Jetzt scheint es so zu sein, daß das Programm nicht häufig genug=20
Idle ist; Im Eingabefeld erscheinen ab und zu kleine Buchstaben=20
bei schneller Eingabe.
Gibt es hierfür noch eine andere Möglichkeit?
Ich kann natürlich beim Übertragen in die Listbox nochmals=20
konvertieren, aber schöner wäre es natürlich schon bei der Eingabe.=
Schönen Gruß aus dem Bergischen Land
Robert
Re: Win32 - Perl/Tk - Eingabe filtern mit validate im Entry-Widget
am 27.04.2007 23:37:00 von Ch Lamprecht
Robert Berghaus schrieb:
> Hallo
>
> Ich versuche mich zur Zeit an einem Dialog mit Eingabefeld und Listbox.
> Das Format fürs Eingabefeld ist: 1-2 Ziffern, beliebige Anzahl
> Leerzeichen und Text
> Der Text darf nur Großbuchstaben enthalten und keine Umlaute. Jetzt will
> ich dem Anwender nicht zumuten, nur Großbuchstaben einzugeben, sondern
> diese selber konvertieren.
> ist; Im Eingabefeld erscheinen ab und zu kleine Buchstaben bei schneller
> Eingabe.
> Gibt es hierfür noch eine andere Möglichkeit?
> Ich kann natürlich beim Übertragen in die Listbox nochmals konvertieren,
> aber schöner wäre es natürlich schon bei der Eingabe.
>
> Schönen Gruß aus dem Bergischen Land
> Robert
>
Hallo,
poste doch einmal ein vollständiges Beispiel, das sich so verhält.
Hier z.B. scheint alles zu funktionieren wie erwartet:
use strict;
use warnings;
use Tk;
my $mw = tkinit;
my $var = 'test';
my $e;
$e = $mw->Entry(-textvariable => \$var,
-validate => 'key',
)->pack;
$e->configure( -validatecommand => sub{validate($e,@_)},
);
$e->validate;
MainLoop;
sub validate{
my $w = shift;
my ($new,undef,undef,$index) = @_;
my $validate = $w->cget('-validate');
my $tv = $w->cget('-textvariable');
$$tv = uc $new;
$w->configure(-validate => $validate);
$w->icursor($index + 1);
return 0;
}
Christoph
--
use Tk;use Tk::GraphItems;$c=tkinit->Canvas->pack;push@i,Tk::GraphItems ->
TextBox(text=>$_,canvas=>$c,x=>$x+=70,y=>100)for(Just=>anoth er=>Perl=>Hacker);
Tk::GraphItems->Connector(source=>$i[$_],target=>$i[$_+1])fo r(0..2);
$c->repeat(30,sub{$_->move(0,4*cos($d+=3.16))for(@i)});MainL oop
Re: Win32 - Perl/Tk - Eingabe filtern mit validate im Entry-Widget
am 28.04.2007 17:24:54 von Robert Berghaus
Hallo Christoph
Ch Lamprecht schrieb:
> Robert Berghaus schrieb:
>> Hallo
>>
>> Ich versuche mich zur Zeit an einem Dialog mit Eingabefeld und=20
>> Listbox. Das Format fürs Eingabefeld ist: 1-2 Ziffern, beliebige=20
>> Anzahl Leerzeichen und Text
>> Der Text darf nur Großbuchstaben enthalten und keine Umlaute. Jetzt =
>> will ich dem Anwender nicht zumuten, nur Großbuchstaben einzugeben, =
>> sondern diese selber konvertieren.
>=20
>
>=20
>> ist; Im Eingabefeld erscheinen ab und zu kleine Buchstaben bei=20
>> schneller Eingabe.
>> Gibt es hierfür noch eine andere Möglichkeit?
>> Ich kann natürlich beim Übertragen in die Listbox nochmals=20
>> konvertieren, aber schöner wäre es natürlich schon bei der Einga=
be.
>>
>> Schönen Gruß aus dem Bergischen Land
>> Robert
>>
> Hallo,
>=20
> poste doch einmal ein vollständiges Beispiel, das sich so verhält.
> Hier z.B. scheint alles zu funktionieren wie erwartet:
>=20
> use strict;
> use warnings;
> use Tk;
>=20
> my $mw =3D tkinit;
> my $var =3D 'test';
> my $e;
> $e =3D $mw->Entry(-textvariable =3D> \$var,
> -validate =3D> 'key',
> )->pack;
)->pack(-fill =3D> 'x',);
> $e->configure( -validatecommand =3D> sub{validate($e,@_)},
> );
> $e->validate;
> MainLoop;
>=20
> sub validate{
> my $w =3D shift;
> my ($new,undef,undef,$index) =3D @_;
> my $validate =3D $w->cget('-validate');
> my $tv =3D $w->cget('-textvariable');
>=20
> $$tv =3D uc $new;
> $w->configure(-validate =3D> $validate);
> $w->icursor($index + 1);
> return 0;
>=20
> }
> Christoph
>=20
>=20
Hier jetzt mein Beispiel. Ich habe nur validate geändert (und ein=20
Kleinigkeit in main), daher auch nur diese sub:
sub validate{
my($w, $sNeu, $sEingabe, $sAlt, $iIndex, $bType) =3D @_;
return 1 if $iIndex == -1;
return 1 unless length($sNeu);
my $val =3D $w->cget('-validate');
my $tv =3D $w->cget('-textvariable');
$w->afterIdle(sub {
$w->configure(
-validate =3D> $val,
-invalidcommand =3D> sub {$w->bell},
);
});
if (defined($sEingabe) && (length($sEingabe) == 1)) {
if ($sEingabe =3D~ /[a-z]/) { # wenn klein, dann groß
$w->delete($iIndex);
$sEingabe =3D uc($sEingabe);
$w->insert($iIndex, $sEingabe);
}
return 1;
}
return 0;
}
Mit Autorepeat oder seht schneller Eingabe) geht es dann manchmal=20
nicht (sehr selten).
Wenn ich Deinen Ansatz richtig verstehe, so benutzt Du validate=20
nur zur Konvertierung und teilst dem Fenster immer mit, daß die=20
Eingabe falsch ist. Das dürfte zwar dem ursprünglichen Zweck=20
widersprechen, aber es gefällt mir.
Einige Fragen hätte ich aber noch ;-)
Warum das:
$e->configure( -validatecommand =3D> sub{validate($e,@_)},
Nach dem Source erweiterst Du damit das Widget um eine Funktion=20
($e->validate;). Ist das so die Vorgehensweise dafür?
In der Sub weist Du die Parameter so zu:
my $w =3D shift;
my ($new,undef,undef,$index) =3D @_;
Warum nicht my ($w,$new,undef,undef,$index) =3D @_; ?
Das eigentliche Problem ist glaub' ich, daß das Eingabefeld nach=20
jedem Aufruf die Prüffunktion deaktiviert. Weist Du, ob das einen=20
bestimmten Grund hat?
Vielen Dank für die Hilfe und schönen Gruß aus dem Bergischen Land
Robert
Re: Win32 - Perl/Tk - Eingabe filtern mit validate im Entry-Widget
am 30.04.2007 12:47:24 von Ch Lamprecht
Robert Berghaus schrieb:
> Hallo Christoph
>
> Ch Lamprecht schrieb:
>
>> Robert Berghaus schrieb:
>>
>>> Hallo
>>>
>>> Ich versuche mich zur Zeit an einem Dialog mit Eingabefeld und
>>> Listbox.
>>> Jetzt
>>> will ich dem Anwender nicht zumuten, nur Großbuchstaben einzugeben,
>>> sondern diese selber konvertieren.
>>
>>
>>
>>
>>> ist; Im Eingabefeld erscheinen ab und zu kleine Buchstaben bei
>>> schneller Eingabe.
>> Hier z.B. scheint alles zu funktionieren wie erwartet:
>>
>> use strict;
>> use warnings;
>> use Tk;
>>
>> my $mw = tkinit;
>> my $var = 'test';
>> my $e;
>> $e = $mw->Entry(-textvariable => \$var,
>> -validate => 'key',
>> )->pack;
>
> )->pack(-fill => 'x',);
>
>> $e->configure( -validatecommand => sub{validate($e,@_)},
>> );
>> $e->validate;
>> MainLoop;
>>
>> sub validate{
>> my $w = shift;
>> my ($new,undef,undef,$index) = @_;
>> my $validate = $w->cget('-validate');
>> my $tv = $w->cget('-textvariable');
>>
>> $$tv = uc $new;
>> $w->configure(-validate => $validate);
>> $w->icursor($index + 1);
>> return 0;
>>
>> }
>> Christoph
>>
>>
>
> Hier jetzt mein Beispiel. Ich habe nur validate geändert (und ein
> Kleinigkeit in main), daher auch nur diese sub:
>
> sub validate{
> my($w, $sNeu, $sEingabe, $sAlt, $iIndex, $bType) = @_;
> return 1 if $iIndex == -1;
> return 1 unless length($sNeu);
> my $val = $w->cget('-validate');
> my $tv = $w->cget('-textvariable');
> $w->afterIdle(sub {
> $w->configure(
> -validate => $val,
> -invalidcommand => sub {$w->bell},
> );
> });
> if (defined($sEingabe) && (length($sEingabe) == 1)) {
> if ($sEingabe =~ /[a-z]/) { # wenn klein, dann groß
> $w->delete($iIndex);
> $sEingabe = uc($sEingabe);
> $w->insert($iIndex, $sEingabe);
> }
> return 1;
> }
> return 0;
> }
>
> Mit Autorepeat oder seht schneller Eingabe) geht es dann manchmal nicht
> (sehr selten).
Das kann ich nachvollziehen.
> Wenn ich Deinen Ansatz richtig verstehe, so benutzt Du validate nur zur
> Konvertierung und teilst dem Fenster immer mit, daß die Eingabe falsch
> ist. Das dürfte zwar dem ursprünglichen Zweck widersprechen,
perldoc Tk::Entry:
With the perl/Tk version validate option is supposed to be "suspended" while
executing the validateCommand or the invalidCommand. This is experimental but in
theory either callback can "correct" the value of the widget, and override the
proposed change. (validateCommand should still return false to inhibit the
change from happening when it returns.)
>
> Einige Fragen hätte ich aber noch ;-)
> Warum das:
> $e->configure( -validatecommand => sub{validate($e,@_)},
> Nach dem Source erweiterst Du damit das Widget um eine Funktion
> ($e->validate;). Ist das so die Vorgehensweise dafür?
Nein, so rufe ich nur meine Funktion 'validate' auf, weil $e im Ernstfall
vielleicht nicht im Scope von 'validate' sichtbar wäre, oder 'validate' auch für
andere Entries benutzt werden könnte. Die anderen Argumente werden erst zur
Ausführungszeit an die anonyme sub gereicht, die sie daher an 'validate'
weitergibt. Falls du in validate auf $e zugreifen kannst, könntest du auch
\&validate schreiben und dort kein shift machen. Es ist aber z.B. für alle
bind-callbacks normal, dass sie das widget als erstes Argument bekommen (da
macht Tk es automatisch).
> In der Sub weist Du die Parameter so zu:
> my $w = shift;
> my ($new,undef,undef,$index) = @_;
> Warum nicht my ($w,$new,undef,undef,$index) = @_; ?
>
Weil mich das widget stört, wenn ich Dumper \@_ anschaue ;)
Oder weil ich es von methoden gewohnt bin. Da ist es praktisch, weil man dann
z.B. $w->SUPER::methode(@_) schreiben kann.
> Das eigentliche Problem ist glaub' ich, daß das Eingabefeld nach jedem
> Aufruf die Prüffunktion deaktiviert. Weist Du, ob das einen bestimmten
> Grund hat?
Vermutlich soll es verhindern, dass Änderungen, die du vom callback aus
vornimmst, erneut validiert werden? Slaven wird es am ehesten wissen.
Christoph
--
use Tk;use Tk::GraphItems;$c=tkinit->Canvas->pack;push@i,Tk::GraphItems ->
TextBox(text=>$_,canvas=>$c,x=>$x+=70,y=>100)for(Just=>anoth er=>Perl=>Hacker);
Tk::GraphItems->Connector(source=>$i[$_],target=>$i[$_+1])fo r(0..2);
$c->repeat(30,sub{$_->move(0,4*cos($d+=3.16))for(@i)});MainL oop
Re: Win32 - Perl/Tk - Eingabe filtern mit validate im Entry-Widget
am 30.04.2007 15:54:47 von Robert Berghaus
Hallo Christoph
[Erstmal Platz schaffen]
Ch Lamprecht schrieb:
> Robert Berghaus schrieb:
>>
>> Mit Autorepeat oder seht schneller Eingabe) geht es dann manchmal=20
>> nicht (sehr selten).
> Das kann ich nachvollziehen.
>=20
Das beruhigt mich doch sehr. Mit Deiner Lösung funktioniert es ja=20
auch einwandfrei.
>> Wenn ich Deinen Ansatz richtig verstehe, so benutzt Du validate nur=20
>> zur Konvertierung und teilst dem Fenster immer mit, daß die Eingabe =
>> falsch ist. Das dürfte zwar dem ursprünglichen Zweck widersprechen=
,
>=20
> perldoc Tk::Entry:
>=20
> With the perl/Tk version validate option is supposed to be "suspended" =
> while
> executing the validateCommand or the invalidCommand. This is=20
> experimental but in
> theory either callback can "correct" the value of the widget, and=20
> override the
> proposed change. (validateCommand should still return false to inhibit =
the
> change from happening when it returns.)
>=20
>=20
Das ging aus dem Buch 'Mastering Perl/Tk' so nicht hervor (oder=20
ich habe es nicht verstanden).
>>
>> Einige Fragen hätte ich aber noch ;-)
>> Warum das:
>> $e->configure( -validatecommand =3D> sub{validate($e,@_)},
>> Nach dem Source erweiterst Du damit das Widget um eine Funktion=20
>> ($e->validate;). Ist das so die Vorgehensweise dafür?
>=20
> Nein, so rufe ich nur meine Funktion 'validate' auf, weil $e im Ernstfa=
ll
> vielleicht nicht im Scope von 'validate' sichtbar wäre, oder 'validat=
e'=20
> auch für andere Entries benutzt werden könnte. Die anderen Argument=
e=20
> werden erst zur Ausführungszeit an die anonyme sub gereicht, die sie =
> daher an 'validate' weitergibt. Falls du in validate auf $e zugreifen=20
> kannst, könntest du auch \&validate schreiben und dort kein shift=20
> machen. Es ist aber z.B. für alle bind-callbacks normal, dass sie das=
=20
> widget als erstes Argument bekommen (da macht Tk es automatisch).
>=20
Bei mir sieht das so aus und da ich validate nicht selber aufrufe,=20
reicht das wohl auch.
$eb =3D $f->Entry(-validate =3D> 'key',
-invalidcommand =3D> sub { $mw->bell },
-textvariable =3D> \$sProgrammName);
$eb->configure(-validatecommand =3D> [\&EingabePruefen, $eb]);
$eb->pack(-side =3D> 'top',
-fill =3D> 'x');
>> In der Sub weist Du die Parameter so zu:
>> my $w =3D shift;
>> my ($new,undef,undef,$index) =3D @_;
>> Warum nicht my ($w,$new,undef,undef,$index) =3D @_; ?
>>
> Weil mich das widget stört, wenn ich Dumper \@_ anschaue ;)
> Oder weil ich es von methoden gewohnt bin. Da ist es praktisch, weil ma=
n=20
> dann
> z.B. $w->SUPER::methode(@_) schreiben kann.
>=20
Hey, das ist ein gutes Argument.
>> Das eigentliche Problem ist glaub' ich, daß das Eingabefeld nach jed=
em=20
>> Aufruf die Prüffunktion deaktiviert. Weist Du, ob das einen bestimmt=
en=20
>> Grund hat?
> Vermutlich soll es verhindern, dass Änderungen, die du vom callback a=
us=20
> vornimmst, erneut validiert werden? Slaven wird es am ehesten wissen.
Das erinnert mich etwas an Interrupt Funktionen, wo dieser auch=20
wieder neu gesetzt werden muß
Vielen Dank für Deine hilfreiche Antwort und schönen Gruß aus dem=20
Bergischen Land
Robert
Re: Win32 - Perl/Tk - Eingabe filtern mit validate im Entry-Widget
am 01.05.2007 20:44:53 von Slaven Rezic
Ch Lamprecht writes:
> Robert Berghaus schrieb:
[...]
>
> > Das eigentliche Problem ist glaub' ich, daß das Eingabefeld nach
> > jedem Aufruf die Prüffunktion deaktiviert. Weist Du, ob das einen
> > bestimmten Grund hat?
> Vermutlich soll es verhindern, dass Änderungen, die du vom callback
> aus vornimmst, erneut validiert werden? Slaven wird es am ehesten
> wissen.
Möglicherweise ist dieser Kommentar in generic/tkEntry.c entscheidend:
* If we were doing forced validation (like via a variable
* trace) and the command returned 0, the we turn off validation
* because we assume that textvariables have precedence in
* managing the value. We also don't call the invcmd, as it
* may want to do entry manipulation which the setting of the
* var will later wipe anyway.
Es sieht also so aus, als ob man -textvariable und -validatecommand
nicht mischen kann, jedenfalls wenn man den Wert der Variablen im
Callback ändert.
Gruß,
Slaven
--
Slaven Rezic - slaven rezic de
need xpm or ppm output from GD?
http://search.cpan.org/search?mode=module&query=GD::Convert
Re: Win32 - Perl/Tk - Eingabe filtern mit validate im Entry-Widget
am 02.05.2007 14:39:26 von Robert Berghaus
Hallo Slaven
Slaven Rezic schrieb:
> Ch Lamprecht writes:
>=20
>> Robert Berghaus schrieb:
> [...]
>>> Das eigentliche Problem ist glaub' ich, daß das Eingabefeld nach
>>> jedem Aufruf die Prüffunktion deaktiviert. Weist Du, ob das einen
>>> bestimmten Grund hat?
>> Vermutlich soll es verhindern, dass Änderungen, die du vom callback
>> aus vornimmst, erneut validiert werden? Slaven wird es am ehesten
>> wissen.
>=20
> Möglicherweise ist dieser Kommentar in generic/tkEntry.c entscheidend=
:
>=20
> * If we were doing forced validation (like via a variable
> * trace) and the command returned 0, the we turn off validation
> * because we assume that textvariables have precedence in
> * managing the value. We also don't call the invcmd, as it
> * may want to do entry manipulation which the setting of the
> * var will later wipe anyway.
>=20
> Es sieht also so aus, als ob man -textvariable und -validatecommand
> nicht mischen kann, jedenfalls wenn man den Wert der Variablen im
> Callback ändert.
>=20
Es ist egal, ob -textvariable benutzt wird oder nicht. Ohne=20
-textvariable ist nur die Bearbeitung etwas anders (aber nicht=20
unbedingt schwieriger). Solange ich im Callback 0 zurückgebe, kann=20
ich auch innerhalb der Funktion "configure(-validate" aufrufen,=20
sonst muß ich wohl "afterIdle" nehmen, damit das außerhalb der=20
Funktion passiert. Bei 'normaler' Eingabe funktioniert "afterIdle"=20
ja auch einwandfrei.
Schönen Gruß aus dem Bergischen Land
Robert