Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]12353[/thread]

POE + Schleifen: Aufruf fällt unter den Tisch

Tags: Ähnliche Threads

Leser: 1


<< >> 2 Einträge, 1 Seite
pktm
 2008-08-14 15:46
#113495 #113495
User since
2003-08-07
2921 Artikel
BenutzerIn
[Homepage]
user image
Hallo!

Ich arbeite da mit POE und Tk. Jetzt habe ich 2 Elemente auf der GUI, die asynchron aktualisiert werden sollen. Da es 2 identische Elemente sind, die einfach nur 2mal vorkommen, bleibt die Methode gleich. Zur Unterscheidung habe ich den beiden Elementen einfach eine distinktive Nummer gegeben.

Mit denen (die 2 Nummern) setze ich 2 asynchron laufende Aufrufe ein und der selben Funktion ab. Die rufen sich jeweils selbst wieder auf.
Um zu wissen, für welche Nummer der Aufruf war muss ein Argument mitgeschleppt werden.

Aber: Wenn ich die beiden Aufrufe absetze fällt einer davon unter den Tisch. Nur der letzte wird weiter verfolgt.
Das ist komisch, denn eigentlich - so hatte ich mir das vorgestellt - müssten doch beide Aufruf-Rekursionen unbehelligt nebeneinander her laufen.

Hier ein komplettes lauffähiges Beispiel. Weil POE manchmal mit anderen Modulen zusammenspielt habe ich alles das, was ich in meinem eigentlichen Programm an Modulen benutze sicherheitshalber drin gelassen.
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/Perl/bin/perl

use strict;
use warnings;

# Tk support is enabled if the Tk module is used before POE itself.
use Tk;
use POE;
use POE qw( Component::EasyDBI );

use Config::Auto;
use Data::Dumper qw/Dumper/;
use DBP::GUIComponents::SmallDemoTab;
use DBP::GUIComponents::BigDemoTab;
use Perl6::Say;
use Tk::Animation;
use Tk::HList;
use Tk::PNG;
use SQL::Abstract;
use Tk::Table;

$Data::Dumper::Sortkeys = 1;

# 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,
custom_loop_initiator => \&custom_loop_initiator,
custom_loop => \&custom_loop,
},
);

# Run the program until it is exited.

$poe_kernel->run();
exit 0;

=head1 METHODEN

=head2 ui_start( ??? )

Create the user interface when the session starts. This assumes
some familiarity with Tk. ui_start() illustrates four important
points.

1. Tk events require a main window. POE creates one for internal
use and exports it as $poe_main_window. ui_start() uses that as the
basis for its user interface.

2. Widgets we need to work with later, such as the counter display,
must be stored somewhere. The heap is a convenient place for them.

3. Tk widgets expect callbacks in the form of coderefs. The
session's postback() method provides coderefs that post events when
called. The Button created in ui_start() fires an "ev_clear" event
when it is pressed.

4. POE::Kernel methods such as yield(), post(), delay(), signal(),
and select() (among others) work the same as they would without Tk.
This feature makes it possible to write back end sessions that
support multiple GUIs with a single code base.

=cut

sub ui_start {
my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ];

# ------------------------------------------------------------
# - Initialisierung

# ------------------------------------------------------
# -- Test: etwas Inhalt einfügen
# ...
# ------------------------------------------------------


# ------------------------------------------------------------
# - 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>',
);

# ------------------------------------------------------------
# - Test-Zeug
testzeug( $heap, $poe_main_window );

# call a recursive looping event
$kernel->yield('custom_loop_initiator', 1);

# now start another one, with another argument
$kernel->yield('custom_loop_initiator', 2);

$kernel->yield("ev_count");
} # /ui_start



=head2 testzeug( $heap, $poe_main_window )

Dient dazu diverses Testzeug auszuführen, z.B: Debugging.
Bei Auslieferung des Programms sollte diese Funktion nichts mehr machen, aber
dennoch enthalten sein damit man später mal schnell was debuggen kann.

=cut

sub testzeug {
my $heap = shift;
my $mw = shift;



} # /testzeug




=head2 custom_loop_initiator( ... )

=cut

sub custom_loop_initiator {
my $session = $_[SESSION];
my $kernel = $_[KERNEL];
my $id = $_[ARG0];

say "init with $id";

$kernel->yield('custom_loop', $id);
} # /custom_loop_initiator




=head2 custom_loop( ... )

=cut

sub custom_loop {
my $kernel = $_[KERNEL];
my $id = $_[ARG0];

say "custom loop with id=$id";

$kernel->delay('custom_loop_initiator' => 2, $id);
} # /custom_loop




=head2 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




=head2 ui_clear

Handle the "ev_clear" event by clearing and redisplaying the
counter.

=cut

sub ui_clear {
$_[HEAP]->{counter} = 0;
} # /ui_clear




=head1 QUELLEN

http://poe.perl.org/?POE_Cookbook/Tk_Interfaces

This sample program creates a very simple Tk counter. Its interface
consists of three widgets: A rapidly increasing counter, and a
button to reset that counter.


Hier ist eine Testausgabe:
Quote
init with 1
init with 2
custom loop with id=1
custom loop with id=2
init with 2
custom loop with id=2
init with 2
custom loop with id=2
...


Wie man schön sieht funktioniert die Rekursion mit der id=2, aber der Aufruf mit id=1 fällt irgendwie unter den Tisch.

Kennt sich jemand aus? Mache ich etwas falsch (könnte man meinen ^^)? Geht's anders?

Grüße, pktm
http://www.intergastro-service.de (mein erstes CMS :) )
pktm
 2008-08-14 18:00
#113499 #113499
User since
2003-08-07
2921 Artikel
BenutzerIn
[Homepage]
user image
Ok, hab jetzt nen Workaround. Die Schleife mit $kernel->delay() wird in custom_loop_initiator bereits ausgeführt, nicht erst in den Methoden, die von diesem Initialisator aufgerufen werden. Ansich schöner, hätte ich auch vorher drauf kommen können. Dafür wird jetzt die nächste ID immer berechnet, der Takt um 50% veringert (sind ja nur 2 Objekte).

Man müsste jetzt noch etwas am Timing spielen...

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
#!/Perl/bin/perl

use strict;
use warnings;

# Tk support is enabled if the Tk module is used before POE itself.
use Tk;
use POE;

use Data::Dumper qw/Dumper/;

$Data::Dumper::Sortkeys = 1;

# 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,
custom_loop_initiator => \&custom_loop_initiator,
custom_loop => \&custom_loop,
},
);

# Run the program until it is exited.

$poe_kernel->run();
exit 0;

=head1 METHODEN

=head2 ui_start( ??? )

Create the user interface when the session starts. This assumes
some familiarity with Tk. ui_start() illustrates four important
points.

1. Tk events require a main window. POE creates one for internal
use and exports it as $poe_main_window. ui_start() uses that as the
basis for its user interface.

2. Widgets we need to work with later, such as the counter display,
must be stored somewhere. The heap is a convenient place for them.

3. Tk widgets expect callbacks in the form of coderefs. The
session's postback() method provides coderefs that post events when
called. The Button created in ui_start() fires an "ev_clear" event
when it is pressed.

4. POE::Kernel methods such as yield(), post(), delay(), signal(),
and select() (among others) work the same as they would without Tk.
This feature makes it possible to write back end sessions that
support multiple GUIs with a single code base.

=cut

sub ui_start {
my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ];

# ------------------------------------------------------------
# - Initialisierung

# ------------------------------------------------------
# -- Test: etwas Inhalt einfügen
# ...
# ------------------------------------------------------
# t=toplevel
$heap->{t}->{1} = MySpecialComponent->new($poe_main_window, 10001);
$heap->{t}->{2} = MySpecialComponent->new($poe_main_window, 20001);

# ------------------------------------------------------------
# - 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>',
);

# ------------------------------------------------------------
# - Test-Zeug
testzeug( $heap, $poe_main_window );

# call a recursive looping event
$kernel->yield('custom_loop_initiator', 1);

# now start another one, with another argument
$kernel->yield('custom_loop_initiator', 2);

$kernel->yield("ev_count");
} # /ui_start




=head2 testzeug( $heap, $poe_main_window )

Dient dazu diverses Testzeug auszuführen, z.B: Debugging.
Bei Auslieferung des Programms sollte diese Funktion nichts mehr machen, aber
dennoch enthalten sein damit man später mal schnell was debuggen kann.

=cut

sub testzeug {
my $heap = shift;
my $mw = shift;



} # /testzeug




=head2 custom_loop_initiator( ... )

Get the value of the label,
increment it by 1 and call
the custom_loop event to
update the label.

=cut

sub custom_loop_initiator {
my $kernel = $_[KERNEL];
my $heap = $_[HEAP];
my $id = $_[ARG0];

my $no = $heap->{t}->{$id}->no();

# invoke the call
$kernel->yield('custom_loop', $id, ++$no);

# Calculate next object to be updated.
my $next_id = ($id == 1 ? 2 : 1);

# do some looping
$kernel->delay('custom_loop_initiator' => 1, $next_id);
} # /custom_loop_initiator




=head2 custom_loop( ... )

=cut

sub custom_loop {
my $kernel = $_[KERNEL];
my $heap = $_[HEAP];
my $id = $_[ARG0];
my $new_no = $_[ARG1];

$heap->{t}->{$id}->no($new_no);


} # /custom_loop




=head2 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




=head2 ui_clear

Handle the "ev_clear" event by clearing and redisplaying the
counter.

=cut

sub ui_clear {
$_[HEAP]->{counter} = 0;
} # /ui_clear




=head1 QUELLEN

http://poe.perl.org/?POE_Cookbook/Tk_Interfaces

This sample program creates a very simple Tk counter. Its interface
consists of three widgets: A rapidly increasing counter, and a
button to reset that counter.

=cut




package MySpecialComponent;

use strict;
use warnings;

=head1 MySpecialComponent

Absolutely useless GUI component. Puts a Label in a toplevel, that will be
created on a given (other) toplevel. Used to demonstarte a problem I have
with POE.



=head1 METHODS

=head2 new( $toplevel, $initial_number )

ctor.

=cut

sub new {
my $class = shift;
my $top = shift or die("Missing toplevel arg.");
my $no = shift or die("Missing a number.");

my $self = bless({}, $class);

$self->{'__TOPLEVEL'} = $top->Toplevel(-title => 'T'.$no);
$self->{'__LABEL'} = $self->{'__TOPLEVEL'}->Label(-text => $no, -width => 40,)->pack();

return $self;
} # /new




=head2 no( $no? )

Getter / setter for the number of this widget.
If $no is given, the label will be set to $no. If it's omitted, only the
current value of the label is returned.
Always returns the current value of the label.

=cut

sub no {
my $self = shift;
my $new_no = shift; # may be undef

# setter
if( defined $new_no ) {
$self->{'__LABEL'}->configure('-text' => $new_no);
return $new_no;
}

# getter
return $self->{'__LABEL'}->cget('-text');
} # /no


1; # /MySpecialComponent
http://www.intergastro-service.de (mein erstes CMS :) )
<< >> 2 Einträge, 1 Seite



View all threads created 2008-08-14 15:46.