Subject: | Problem with Tk loop |
Date: | Mon, 11 Jun 2012 22:29:52 +0200 |
To: | <bug-poe [...] rt.cpan.org> |
From: | "Alex" <capfan [...] gmx.de> |
Dear recipient,
I got this of one of my scripts:
[quote]
please report this stacktrace to bug-poe@rt.cpan.org at
C:/Perl/site/lib/POE/Kernel.pm line 1013
POE::Kernel::_dispatch_event('POE::Kernel=ARRAY(0x43a05b4)',
undef, 'POE::Kernel=ARRAY(0x43a05b4)', '_child', 128, 'ARRAY(0x4c3c914)',
'C:/Perl/site/lib/POE/Kernel.pm', 1454, undef, ...) called at
C:/Perl/site/lib/POE/Kernel.pm line 1452
POE::Kernel::session_alloc('POE::Kernel=ARRAY(0x43a05b4)',
'POE::Session=ARRAY(0x3d93f84)') called at C:/Perl/site/lib/POE/Session.pm
line 192
POE::Session::try_alloc('POE::Session=ARRAY(0x3d93f84)')
called at C:/Perl/site/lib/POE/Session.pm line 373
POE::Session::create('POE::Session', 'inline_states',
'HASH(0x46944d4)', 'args', 'ARRAY(0x4694664)') called at
C:\Perl\Skripten\tk\apache_log_parser\apacheLogParser_tk.pl line 76
=== 3420 === Sessions were started, but POE::Kernel's run() method was never
called to execute them. This usually happens because an error
occurred before POE::Kernel->run() could be called. Please fix
any errors above this notice, and be sure that POE::Kernel->run()
is called. See documentation for POE::Kernel's run() method for
another way to disable this warning.
[/quote]
I will include the code, too.
Here is what I did: I use ActiveState Perl and Tk with POE. My script works
fine, unless I add a $poe_main_window->update() statement somewhere before
the $kernel-run()-method. Then, it crashed.
I tried to get the windows' dimensions live before configuring the Tk::Menu
of the window, because if I don't, the window will be display the menu only:
HTH,
Alex
Script (NB: its commented in german because its intended as instruction
script for Germans):
#!/Perl/bin/perl
=head1 NAME
apacheLogParser_tk.pl - ein Programm zum überwachen von Dateien
=head1 BESCHREIBUNG
Im Quelltext findet sich ein Abschnitt, in dem die zu überwachenden Dateien
eingetragen werden können.
Diese Dateien werden dann automatisch auf Änderungen geprüft.
=head2 VERWENDUNG
Die zu überwachenden Dateien in @logdateien eintragen, Programm starten.
=cut
use strict;
use warnings;
use Config::Auto;
use Data::Dumper qw/Dumper/;
use File::Spec;
use DBIx::NoSQL;
use utf8;
use vars qw($VERSION);
$VERSION = 0.3;
# Tk support is enabled if the Tk module is used before POE itself.
use Tk;
use Tk::ToolBar;
use Tk::StatusBar;
# except when it isn't...
#
# ActiveState does something funky such that if you don't include
# Loop::TkActiveState here Loop::Tk won't be detected. The good news
# is that it does not appear to be necessary to special case this for
# other platforms.
use POE qw( Loop::TkActiveState Wheel::FollowTail );
# Datenbank initialisieren, in der die Konfigurationsparameter gespeichert
werden.
# Die Datenbank wird automatisch erstellt, wenn noch keine vorhanden ist.
my $store = DBIx::NoSQL->connect( 'store.sqlite' );
# Definiere globale Variablen zum Programm
# ToDo: Konfigurationsdatei verwenden, Dialog zum hinzufügen und Entfernen
der
# Dateien anlegen.
my $logdateien = $store->exists( 'Files', 'watched' );
unless( $logdateien ) {
$logdateien = [];
}
#my $logdateien = [
# File::Spec->catfile(qw(c: Apache logs error.log)),
# File::Spec->catfile(qw(c: Apache logs access.log)),
#];
# Dubletten entfernen
my %seen = ();
@{$logdateien} = grep { ! $seen{ $_ }++ } @{$logdateien};
undef %seen;
foreach( @{$logdateien} ) {
die "Logdatei [$_] existiert nicht!\n" unless -e $_;
}
# Create the session that will drive the user interface.
POE::Session->create(
inline_states =>
{ _start => \&ui_start,
ev_count => \&ui_count,
ev_clear => \&ui_clear,
got_line => \&updateLog_line,
got_error => \&updateLog_error,
},
args => \@{$logdateien},
);
# Run the program until it is exited.
$poe_kernel->run();
exit 0;
=head2 METHODEN
=head3 ui_start
Baut die grafische Oberfläche zusammen. Pro angegebene Log-Datei gibt es
einen
Notebook-Reiter.
ToDo: Wenn die Reiter breiter sind als das Fenster sollte ein Scroll-Teil
an der Seite erscheinen, oder irgend eine andere Möglichkeit geboten werden
auf diese Reiter zuzugreifen.
Reiter scheinen sowieso irgendwie ungeeigenet zu sein, einzelne Fenster
wären
wohl besser.
=cut
sub ui_start {
my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ];
# -- Fenstergröße ungefähr anpassen
die "could not create a main Tk window" unless defined $poe_main_window;
$poe_main_window->configure(-width => 1280, -height => 480,);
$poe_main_window->packPropagate(0);
#$poe_main_window->update();
# -- Menu erstellen
my $menuitems = [
[Cascade => "~Datei", -menuitems =>
[
[Button => "~Neu", -command => \&new],
[Separator => ""],
[Button => "~Öffnen", -command => \&open],
[Button => "~Sichern", -command => \&save],
],
],
];
my $menu = $poe_main_window->Menu(-menuitems => $menuitems);
$poe_main_window->configure(-menu => $menu);
# -- TK-GUI erstellen
require Tk::NoteBook;
$heap->{notebook} = $poe_main_window->NoteBook();
foreach my $logdatei ( @{$logdateien} ) {
$heap->{notebookSeiten}{$logdatei}{seite} =
$heap->{notebook}->add($logdatei, -label => $logdatei,);
$heap->{notebookSeiten}{$logdatei}{scr_txt} =
$heap->{notebookSeiten}{$logdatei}{seite}->Scrolled(
# keine Eigenschaften wie Höhe oder Breite, weil das Textfeld
skalierbar sein soll.
Text => -scrollbars => 'se',
)->pack(-expand => 1, -fill => 'both',);
# -- Buttons für Funktionen erstellen
$heap->{notebookSeiten}{$logdatei}{btn_frame} =
$heap->{notebookSeiten}{$logdatei}{seite}->Frame();
$heap->{notebookSeiten}{$logdatei}{clear_btn} =
$heap->{notebookSeiten}{$logdatei}{btn_frame}->Button(
-text => 'Anzeige leeren',
-command => sub{
$heap->{notebookSeiten}{$logdatei}{scr_txt}->Subwidget('scrolled')->delete("
0.0", "end");
#print "$logdatei\n";
#print Dumper
$heap->{notebookSeiten}{$logdatei}{scr_txt}->Subwidget('scrolled'); # =
undef???
},
)->pack(-side => 'left',);
$heap->{notebookSeiten}{$logdatei}{btn_frame}->pack(-side =>
'left',);
}
$heap->{notebook}->pack(-expand => 1, -fill => 'both',);
# -- Statusbar
# -> für den UI-Counter
require Tk::StatusBar;
$heap->{statusbar} = $poe_main_window->StatusBar();
$heap->{statusbar}->addLabel(
-relief => 'flat',
-text => "Welcome to the statusbar",
);
$heap->{statusbar}->addLabel(
-text => 'Frame:',
-width => '10',
-anchor => 'center',
);
$heap->{statusbar}->addLabel(
-width => 20,
-anchor => 'center',
-textvariable => \$heap->{counter},
-foreground => 'blue',
);
$heap->{statusbar}->addLabel(
-width => 10,
-anchor => 'center',
-text => "Clear",
-foreground => 'blue',
-command => $session->postback("ev_clear"),
-event => '<Button-1>',
);
# -- Wheel erstellen um die Error.log zu überwachen
foreach( @{$logdateien} ) {
$heap->{wheel}->{$_} = POE::Wheel::FollowTail->new(
Filename => $_,
InputEvent => 'got_line',
ErrorEvent => 'got_error',
SeekBack => 1024,
);
}
$heap->{first} = 0;
# Loop starten
$kernel->yield("ev_count");
} # /ui_start
=head3 ui_count
Handle the "ev_count" event by increasing a counter and displaying
its new value.
=cut
sub ui_count {
$_[HEAP]->{counter}++;
$_[KERNEL]->yield("ev_count");
} # /ui_count
=head3 ui_clear
Handle the "ev_clear" event by clearing and redisplaying the counter.
=cut
sub ui_clear {
$_[HEAP]->{counter} = 0;
} # /ui_clear
=head3 updateLog_line
Fügt die neuen Informationen aus den zu verfolgenden Dateien im
entsprechenden
Reiter an. In $_[ARG0] scheint dabei das zu stehen, was bei der gerade
modifizierten
Datei angehangen wurde und in $_[ARG1] die Nummer (beginnend bei 1) der
Datei in der Liste der zu verfolgenden Dateien ( siehe args - Argument bei
POE::Session->create() ).
Ideen: Flashen der Reiter wenn ein Update erfolgt ist. Automatisches
Scrollen
als Option (an|aus), umdrehen der einzelnen Datei-Abschnitte (geht z.B. bei
Apache-Logdateien) um den aktuellen Eintrage immer oben zu haben.
=cut
sub updateLog_line {
my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ];
my $eingabe = $_[ARG0];
#print STDERR Dumper $_[ARG0];
my @eingaben = split m/\\r, /, $eingabe;
foreach my $eing ( @eingaben ) {
$heap->{notebookSeiten}{$logdateien->[($_[ARG1]-1)]}{scr_txt}->insert("end",
"normal: $eing\n") if $heap->{first}++;
}
} # /updateLog_line
=head3 updateLog_error
Keine Ahnung was das hier macht...
=cut
sub updateLog_error {
warn "$_[ARG0]\n";
} # /pdateLog_error
=head2 QUELLEN
=over
=item * L<http://poe.perl.org/?POE_Cookbook>
=over
=item a) POE+Tk - Rezept L<http://poe.perl.org/?POE_Cookbook/Tk_Interfaces>
=item b) POE+Wheel::FollowTail - Rezept
L<http://poe.perl.org/?POE_Cookbook/Watching_Logs>
=back
=back
=head2 AUTOR
Alexander Becker, asb_ehb doYouKnowWhatToInsertHere? yahoo.de
=head2 SIEHE AUCH
=over
=item * L<TK>
=item * L<POE>
=item * L<http://poe.perl.org/?POE_Cookbook/Tk_Interfaces>
=item * L<http://www.perl-community.de>
=back
Message body is not shown because it is too large.