Um vom Benutzer erzeugte Ereignisse abzufragen, gibt es die Methode bind. Ein häufiger Anwendungsfall ist bei einer Eingabe in einer Textbox (Entry) die Return-Taste abzufangen
#!perl
use strict;
use warnings;
use Tk;
my $mw = MainWindow->new();
my $eingabe = "Passwortabfrage";
my $f1 = $mw->Frame()->pack(-side => 'top');
my $f2 = $mw->Frame(
-relief => 'sunken',
-borderwidth => '10',
)->pack(-side => 'top');
my $f3 = $mw->Frame()->pack(-side => 'top');
my $f4 = $mw->Frame(
-relief => 'groove',
-borderwidth => '10',
)->pack(-side => 'top');
my $text = $f1->Label(-text => 'Passwort eingeben (Pinguine):')->pack();
my $inp = $f2->Entry()->pack();
my $out = $f3->Label(-textvariable => \$eingabe)->pack();
$inp->bind('<Return>', \&input);
$mw->MainLoop();
sub input {
if ($inp->get() eq "Pinguine") {
$eingabe = "Passwort richtig";
$inp->delete(0, 'end');
my $schalter = $f4->Button(
-text => "Weiter",
-command => sub {$mw->destroy()},
)->pack();
}else{
$eingabe = "Passwort falsch";
$inp->delete(0, 'end');
}
}
So sieht das Ergebnis aus:
Hier haben Sie eine sehr einfache Passwortabfrage. Bei Eingabe des richtigen Passwortes (Pinguine) erscheint der Button zum Weitermachen. Uns interessiert in diesem Beispiel aber
$inp->bind('<Return>', \&input)
Damit verknüpfen Sie das Eingabe-Textfeld mit dem Tastatur-Code RETURN.
Wenn Sie also im Eingabebereich die Taste ENTER betätigen, wird die
Callback-Funktion input
ausgeführt.
Es gibt viele Ereignisse, für die man Callback-Funktionen hinterlegen kann,
einige davon sind:
Modifikator | Bedeutung | Beispiel |
---|---|---|
Control | Die Taste Control (oder Steuerung) muss gedrückt sein. | <Control-c> |
Shift | Die Shift-Taste muss gedrückt sein. | <Shift-F5> |
Lock | Die Lock-Taste muss gedrückt sein. | <Lock-7> |
Alt | Die Alt-Taste muss gedrückt sein. | <Alt-d> |
Button | Der angegebene Mausbutton muss gedrückt sein. | <Button-1-Button-3> |
Double | Es muss etwas zweimal passieren. | <Double-Button-1> |
Triple | Es muss etwas dreimal passieren. | <Triple-Button-1> |
Enter | Maus betritt das Widget. | <Enter> |
Leave | Maus verlässt das Widget. | <Leave> |
Randbemerkung: Für bessere Passworteingaben kann man dem Entry-Element die
Option -show => '*'
mitgeben, dann werden statt der eingegebenen Zeichen nur
Sternchen angezeigt.
Nun eine Anwendung, wo mit der Verwendung der Return-Taste zum nächsten
Eingabefeld eines Formulars weitergeschaltet wird.
Dafür muss noch kurz die verwendete Methode focus erklärt werden:
$widget->focus()
gibt dem angegebenen Element den Fokus, d.h. es wird aktiv
und nimmt Tastatureingaben entgegen, falls es dies kann.
Hier das Beispielprogramm:
#!perl
use strict;
use warnings;
use utf8;
use Tk;
my $mw = MainWindow->new();
$mw->Label(-text => 'Vorname:')->pack(-anchor => 'w');
my $evn = $mw->Entry()->pack(-fill => 'x');
$mw->Label(-text => 'Nachname:')->pack(-anchor => 'w');
my $enn = $mw->Entry()->pack(-fill => 'x');
$mw->Label(-text => 'Straße:')->pack(-anchor => 'w');
my $est = $mw->Entry()->pack(-fill => 'x');
$mw->Label(-text => 'Hausnummer:')->pack(-anchor => 'w');
my $ehn = $mw->Entry()->pack(-fill => 'x');
$mw->Label(-text => 'Postleitzahl:')->pack(-anchor => 'w');
my $epl = $mw->Entry()->pack(-fill => 'x');
$mw->Label(-text => 'Ort:')->pack(-anchor => 'w');
my $eor = $mw->Entry()->pack(-fill => 'x');
my $btn = $mw->Button(
-text => 'OK',
-command => sub {
print "Vorname : ", $evn->get(), "\n",
"Nachname : ", $enn->get(), "\n",
"Straße : ", $est->get(), "\n",
"Hausnummer : ", $ehn->get(), "\n",
"Postleitzahl: ", $epl->get(), "\n",
"Ort : ", $eor->get(), "\n";
$mw->destroy();
},
)->pack();
$evn->bind('<Return>', sub { $enn->focus() });
$enn->bind('<Return>', sub { $est->focus() });
$est->bind('<Return>', sub { $ehn->focus() });
$ehn->bind('<Return>', sub { $epl->focus() });
$epl->bind('<Return>', sub { $eor->focus() });
$eor->bind('<Return>', sub { $btn->focus() });
$evn->focus();
$mw->MainLoop();
So sieht das Ergebnis aus:
Ausgabe im obigen Fall:
Vorname : Peter
Nachname : Mustermann
Straße : Musterstraße
Hausnummer : 123
Postleitzahl: 12345
Ort : Musterhausen
An dieser Stelle sollte man nicht verschweigen, dass sich wiederholende Dinge
wie im obigen Programm für Automatisierungen eignen.
Deshalb folgt hier ein Programm, das das gleiche leistet wie das Programm
bind2.pl, aber bei welchem Änderungen in den Formularfeldern nur an einer
einzigen Stelle vorgenommen werden müssen, nämlich bei der Definition des
Arrays @felder
.
Aussehen und Ausgabe stimmt mit obigem Programm überein.
#!perl
use strict;
use warnings;
use utf8;
use Tk;
my $mw = MainWindow->new();
my @felder = (
'Vorname',6
'Nachname',
'Straße',
'Hausnummer',
'Postleitzahl',
'Ort',
);
my @ee;
for my $feld (@felder) {
$mw->Label(-text => $feld . ':')->pack(-anchor => 'w');
push @ee, $mw->Entry()->pack(-fill => 'x');
}
my $btn = $mw->Button(
-text => 'OK',
-command => sub {
for my $i (0..$#felder) {
printf "%-12s: %s\n", $felder[$i], $ee[$i]->get();
}
$mw->destroy();
},
)->pack();
for my $i (0..$#felder-1) {
$ee[$i]->bind('<Return>', sub { $ee[$i+1]->focus() });
}
$ee[$#felder]->bind('<Return>', sub { $btn->focus() });
$ee[0]->focus();
$mw->MainLoop();
Hier ist der Unterschied noch nicht sehr deutlich, bei 20 Feldern wäre er auffälliger.
Kurze Erklärung: Im Array @felder
werden die Namen der Eingabefelder
festgelegt. Zu jedem Feld wird ein Label mit dem entsprechenden Text und ein
Entry angelegt, das Entry wird im Array @ee
abgelegt (in der gleichen
Reihenfolge wie die Feldnamen).
Dadurch lässt sich die Erzeugung der Label und Entrys, die Callback-Funktion des OK-Buttons und die Vergabe der Bindungen in Schleifen vereinfachen.
Bei den Bindungen nimmt das letzte Entry einen Sonderplatz ein, weil der Fokus hier nicht auf das nächste Entry, sondern auf den Button übergeht.
Ruft man $widget->bind()
ohne Parameter auf, so erhält man eine Liste aller
Bindungen, die für dieses Widget erzeugt worden sind.
Mit $widget->bind('<Button-1>')
lässt sich ermitteln, welche Callbacks für
den linken Mausclick eingetragen sind.
Mit $widget->bind('<Button-1>', '')
lässt sich die Bindung des Klickens mit
der linken Maustaste an dieses Widget wieder löschen.
Mehr hierzu findet man unter Tk::bind auf CPAN oder im Abschnitt über Ereignisse in der Perl/Tk-Einführung.