Wx::Panel->new( $frame, -1); das Panel das automatisch die ganze Fläche des Fensters (Elternwidget im ersten Parameter, zweiter Parameter ist autogenerierte WidgetID) einnimmt, wie es der Knopf im vorigen Kapitel tat.
Panel können aber auch Teilflächen eines Fensters sein, für optische Einheiten die man zusammen ein und ausblenden will, wie Schaltflächen eines Konfigurationsdialoges oder Flächen die eine Reiterleiste aufklappt.
Wx::BoxSizer->new(wxHORIZONTAL); erstellt wird sollte jetzt wirklich niemand mehr überraschen, auch das wxHORIZONTAL erklärt sich fast von selbst, da so ein gummi ja bloss waagerecht (xwHORIZONTAL) oder senkrecht (xwVERTICAL) gespannt werden kann. Das Auffädeln macht man dann mit der Methode Add, wobei man natürlich auch mit Insert oder Remove jederzeit noch was einfügen oder löschen kann. Vergesst nicht danach $sizer->Layout aufzurufen damit euere Änderung aus sichtbar wird.
Add auf mehrere Arten rufen kann mach ich es meistens indem ich ihm 4 Parameter übergebe. 1. eine Referenz auf das Widget, 2. ein Proportion-Flag (0/1) je nach dem ob das Widget seine Grösse behalten soll oder sich prozentual mit dem Fenster mitvergrössern soll. 3. wxFlags die angeben nach welcher Richtung ihr das Element ausrichten wollte (wxTOP, wxBOTTOM, wxLEFT, wxRIGHT) 4. Rand in Pixel. Statt zwischen die Widgets aufwendig WxSpacer einzufügen die für Abstand zwischen den Elementen sorgen, kann man auch gleich im Add angeben wieviel Abstand das Widget zum "Vordermann" lassen soll. Dabei auch Richtung beachten, weil diese Angabe bei wxLEFT den linken und bei wxRIGHT den rechten Rand betrifft.
Wx::BoxSizer. Dazu kann man die Gridsizer nehmen, die ein Raster über das Fenster legen, in deren Zellen man die Widgets ablegen kann oder man kann auch die BoxSizer schachteln was weit mehr Möglichkeiten offen lässt. Dazu übergibt man beim $sizer->Add() einfach einen anderen Sizer anstatt eines Widget, der Rest läuft wie oben beschrieben und kann hier auch im Beispiel nachgelesen werden. Einzig neu ist das wxGROW, mit dem ich die Untersizer der ersten beiden Zeilen an den Hauptsizer knüpfe. Dieses Flag befiehlt den Sizern (oder einem Widget) den gesamten restlichen verfügbaren Platz einzunehmen. Manche mögen jetzt meinen, dazu könnte man den vorigen Parameter auf 1 setzen aber dies ist ein Irrtum, denn ein BoxSizer denkt nur eindimensional. Der Haupsizer ist ein senkrechter, wenn der durch die 1 im zweiten Parameter die Info bekommt: "ja gib dem Widget den restlichen Platz", dann betrifft das nur die Y-Ausdehnung. Sagt aber der Haupsizer dem waagerecht denkenden Untersizer mit dem =wxGROW=-Flag "du kriegst all den restlichen Platz", dann nimmt er sich die gesammt Breite des Fensters die noch frei ist. Spätestens wenn man das Beispielprogramm startet und das Fenster in Höhe und Breite grösser zieht, sieht man sofort wie Wx hier die Situation versteht.
Wx::TextCtrl genommen. Die meissten Werte die ich dem Textfeld bei der Erzeugung (new) gebe, halten sich an das bekannte Schema, erwähnenswert sind nur das ich als Style-Konstante wxTE_RIGHT angebe, was den Text rechtsbündig macht und das ich ihm nicht die Konstante wxTE_MULTILINE gebe, wodurch das Feld einzeilig bleibt. Und damit die aktuelle Gleichung auch ausgewertet wird wenn an innerhalb des Textfeldes Enter drückt, habe ich die Subroutine die das macht auch mit dem Event EVT_TEXT_ENTER des Feldes verknüpft.
| handrechner.pl |
use strict;
use warnings;
Handrechner->new->MainLoop;
package Handrechner;
use base qw(Wx::App);
use Wx qw (wxVERTICAL wxHORIZONTAL wxTOP wxLEFT wxGROW wxTE_RIGHT);
use Wx::Event qw( EVT_BUTTON EVT_TEXT_ENTER );
sub OnInit {
my $frame = Wx::Frame->new( undef, -1, 'Wx Rechner', [-1,-1], [160, 228]);
my $panel = Wx::Panel->new( $frame, -1);
my $term = $panel->{'term'} = Wx::TextCtrl->new( $panel, -1, '', [-1,-1], [-1,-1], wxTE_RIGHT );
for my $label (0..9,'=','+','-','*','/','.','+/-','<-|', 'C' ) {
$panel->{button}{$label} = Wx::Button->new( $panel, -1, " $label ", [-1,-1], [25,-1]);
EVT_BUTTON($panel, $panel->{button}{$label}, sub {
$term->AppendText($label);
Wx::Window::SetFocus($term);
} );
}
EVT_BUTTON($panel, $panel->{button}{'+/-'}, sub { } );
EVT_BUTTON($panel, $panel->{button}{'<-|'}, sub {
my $pos = $term->GetInsertionPoint;
$term->Remove($pos-1, $pos);
Wx::Window::SetFocus($term);
} );
EVT_BUTTON($panel, $panel->{button}{'C'}, sub {
$term->Clear;
Wx::Window::SetFocus($term);
} );
EVT_BUTTON($panel, $panel->{button}{'='}, \&eval_term );
EVT_TEXT_ENTER($panel, $term, \&eval_term);
my $h_sizer = Wx::BoxSizer->new(wxVERTICAL);
my $r0_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
$r0_sizer->Add( $term, 1, wxLEFT, 5 );
$r0_sizer->AddSpacer(5);
my $r1_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
$r1_sizer->Add( $panel->{button}{'C'}, 0, wxLEFT, 5 );
$r1_sizer->Add($panel->{button}{'<-|'}, 0, wxLEFT, 5 );
$r1_sizer->Add( $panel->{button}{'='}, 1, wxLEFT, 48 );
$r1_sizer->AddSpacer(5);
my $r2_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
$r2_sizer->Add( $panel->{button}{1}, 0, wxLEFT, 5 );
$r2_sizer->Add( $panel->{button}{2}, 0, wxLEFT, 5 );
$r2_sizer->Add( $panel->{button}{3}, 0, wxLEFT, 5 );
$r2_sizer->Add( $panel->{button}{'+'},0, wxLEFT,25 );
my $r3_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
$r3_sizer->Add( $panel->{button}{4}, 0, wxLEFT, 5 );
$r3_sizer->Add( $panel->{button}{5}, 0, wxLEFT, 5 );
$r3_sizer->Add( $panel->{button}{6}, 0, wxLEFT, 5 );
$r3_sizer->Add( $panel->{button}{'-'},0, wxLEFT,25 );
my $r4_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
$r4_sizer->Add( $panel->{button}{7}, 0, wxLEFT, 5 );
$r4_sizer->Add( $panel->{button}{8}, 0, wxLEFT, 5 );
$r4_sizer->Add( $panel->{button}{9}, 0, wxLEFT, 5 );
$r4_sizer->Add( $panel->{button}{'*'},0, wxLEFT,25 );
my $r5_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
$r5_sizer->Add( $panel->{button}{'.'}, 0,wxLEFT, 5 );
$r5_sizer->Add( $panel->{button}{'0'}, 0,wxLEFT, 5 );
$r5_sizer->Add($panel->{button}{'+/-'},0,wxLEFT, 5 );
$r5_sizer->Add( $panel->{button}{'/'}, 0,wxLEFT,25 );
$h_sizer->Add( $r0_sizer, 0, wxTOP|wxGROW, 7 );
$h_sizer->Add( $r1_sizer, 0, wxTOP|wxGROW, 15 );
$h_sizer->Add( $r2_sizer, 0, wxTOP, 15 );
$h_sizer->Add( $r3_sizer, 0, wxTOP, 5 );
$h_sizer->Add( $r4_sizer, 0, wxTOP, 5 );
$h_sizer->Add( $r5_sizer, 0, wxTOP, 5 );
$panel->SetSizer($h_sizer);
$panel->SetAutoLayout(1);
$frame->Show(1);
}
sub eval_term {
my $term = shift->{'term'};
$term->SetValue( eval($term->GetValue) ) if $term->GetValue;
$term->SetInsertionPointEnd;
Wx::Window::SetFocus($term);
} |