GUI mit Perl/Tk

Perl/Tk-Tutorial

Kapitel 11: Steuerelement - bind

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

bind1.pl

#!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:

tk18.png

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:

bind2.pl

#!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:

Formular in Perl/Tk, bei Enter springt der Cursor in das nächste Feld

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.

bind3.pl

#!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.

Top