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

Button dyn. mit Array erzeugen



<< >> 8 Einträge, 1 Seite
Hagen
 2007-11-18 23:23
#102543 #102543
User since
2007-09-06
233 Artikel
BenutzerIn
[default_avatar]
Hallo,

ich versuche gerade Buttons dynamische zu erzeugen. Leider tritt dabei ein Fehler auf, den ich (bisher) nicht so ganz verstehen.

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use strict;
use warnings;
use Tk;
...
  my $mainw = new MainWindow(-title => "TK Scrip-Starter");
...
  # create buttons
  my @btn;
  for (my $i = 0; $i < @subs; $i++) {
    print "--> $subs[$i]\n";
    $btn[$i] = $mainw->Button(-text    => 'sub "'.$subs[$i].'" ('.$i.')',
                              -anchor => 'w',
                              -command => sub { print "-".$subs[$i]."-".$i."\n"; },  
                              )
    ->pack();
    } # for 
...
  MainLoop;


Die print Anweisung macht noch keinen wirklichen Sinn, ist mehr für die Testphase. Allerdings bereitet genau diese ein Problem.

Der Button-Text wird richtig und wie erwartet dargestellt. Aber innerhalb der print-Anweisung wird immer auf ein nicht vorhandenes Element zugegriffen ($i ist größer als @subs). Wenn z.B. @subs 2 Elemente entält, wird bei beiden (!) erzeugten Buttons auf subs[2] zugegriffen.

Ich verstehe aber nicht warum bzw. wie man das ändern könnte.
Gruß
Hagen
ptk
 2007-11-18 23:35
#102544 #102544
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
Du kannst beispielsweise in der for-Schleife als erstes eine Zuweisung
Code: (dl )
my $j = $i;
machen und im Closure $j statt $i verwenden.

Oder du verwendest ein spezielles Perl/Tk-Konstrukt für Callbacks:
Code: (dl )
-command => [sub { my $i = shift; print "-".$subs[$i]."-".$i."\n"; }, $i],
lichtkind
 2007-11-18 23:42
#102545 #102545
User since
2004-03-22
5697 Artikel
ModeratorIn + EditorIn
[Homepage]
user image
natürlich zu allererst bitte benutze die kürzere und elegantere schleifenform

Code (perl): (dl )
for my $i (0 .. $#subs){


und dann bedenke bitte das wenn der knopf gedrückt wird die schleife schon lange durchgelaufen ist also $i dann einen wert hat den er nach abarbeitung der schleife hatte. mit den label gibt es kein problem da die beim schleifendurchlauf evaluiert werden aber die coderef die du mit der anonymen sub erstellst wird ja erst später ausgewertet.

um dein problem zu lösen fallen mir 2 möglichkeiten ein.
1. du erstellt im schleifenblock eine lokale variable, eine closure, die weiterhin den benötigten wert behält. oder du evaluierst den inhalt der sub mit den werten vom aktuellen $i. klingt vielleicht etwas umständlich aber ich meine sowas wie:

Code (perl): (dl )
-command => eval 'sub {print -'.$subs[$i].'-'.$i."\n"; }",  


ist jetzt ungetestet also kan sein das da ne referenz fehlt, aber auf die art mach ich es in meinem editor auch an einigen stellen.
Wiki:Tutorien in der Wiki, mein zeug:
kephra, baumhaus, garten, gezwitscher

Es beginnt immer mit einer Entscheidung.
lichtkind
 2007-11-18 23:44
#102546 #102546
User since
2004-03-22
5697 Artikel
ModeratorIn + EditorIn
[Homepage]
user image
huch da hat ja noch jemand geantwortet :)
Wiki:Tutorien in der Wiki, mein zeug:
kephra, baumhaus, garten, gezwitscher

Es beginnt immer mit einer Entscheidung.
Spieler
 2007-11-19 00:01
#102547 #102547
User since
2007-09-24
70 Artikel
BenutzerIn
[default_avatar]
lichtkind+2007-11-18 22:42:58--
natürlich zu allererst bitte benutze die kürzere und elegantere schlefenform

Code (perl): (dl )
for my $i (0 .. $#subs){

Und noch ein weiterer Kommentar: Hiermit wäre das Problem ja schon gelöst ;)

Grüße, Christoph
Hagen
 2007-11-19 11:13
#102553 #102553
User since
2007-09-06
233 Artikel
BenutzerIn
[default_avatar]
Danke für die Antworten, habe sie alle ausprobiert und bis auf die Lösung mit 'eval' habe ich es mit den anderen hinbekommen, danke!

lichtkind+2007-11-18 22:42:58--
Code (perl): (dl )
for my $i (0 .. $#subs){


Könntest du/einer mir mal erklären was die Zeile genau macht bzw. warum das damit funktioniert? Ein
Code (perl): (dl )
for my $i (0 .. @subs){

würde ich verstehen.

lichtkind+2007-11-18 22:42:58--
und dann bedenke bitte das wenn der knopf gedrückt wird die schleife schon lange durchgelaufen ist also $i dann einen wert hat den er nach abarbeitung der schleife hatte. mit den label gibt es kein problem da die beim schleifendurchlauf evaluiert werden aber die coderef die du mit der anonymen sub erstellst wird ja erst später ausgewertet.


Das hatte ich mir auch überlegt. Nur hatte ich 'damals' keine Idee, wie ich die Daten hätte speichern können.
Code (perl): (dl )
my $j = $i;

wäre das nahe liegenste gewesen. Bin nur leider nicht darauf gekommen.
Gruß
Hagen
renee
 2007-11-19 11:27
#102554 #102554
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
Hagen+2007-11-19 10:13:39--

lichtkind+2007-11-18 22:42:58--
Code (perl): (dl )
for my $i (0 .. $#subs){


Könntest du/einer mir mal erklären was die Zeile genau macht bzw. warum das damit funktioniert? Ein
Code (perl): (dl )
for my $i (0 .. @subs){

würde ich verstehen.


0..$x erzeugt eine Liste mit den Zahlen von 0 bis (enschließlich) $x. Also würde aus 0..5 ein 0,1,2,3,4,5 werden. Dazu kannst Du einfach mal das hier machen:
Code (perl): (dl )
1
2
my @liste = (0..10);
print $_,"\n" for @liste;


@subs liefert im Skalaren Kontext die Anzahl der Elemente. Ein 0..$anzahl würde - wenn das Array 3 Elemente hat - folgendes liefern: 0,1,2,3. Das Array hat aber kein Element mit dem Index 3!

$#subs liefert den Index des letzten Elements. Ein 0..$last_index liefert also 0,1,2. Und das ist was Du willst. Zur Veranschaulichung kannst Du ja mal folgendes machen:

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use strict;
use warnings;

my @liste = (0..10);

my $anzahl = @liste;
my $last_index = $#liste;

print qq~
Anzahl der Elemente: $anzahl
Index letztes Element: $last_index
========================
~;

for( 0..$anzahl ){
    print 'Element bei 0..$anzahl: ', $liste[$_]," (Index: $_)\n";
}

for( 0..$last_index ){
    print 'Element bei 0..$anzahl: ', $liste[$_]," (Index: $_)\n";
}
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
Hagen
 2007-11-20 00:27
#102616 #102616
User since
2007-09-06
233 Artikel
BenutzerIn
[default_avatar]
Dank für die Info!
Gruß
Hagen
<< >> 8 Einträge, 1 Seite



View all threads created 2007-11-18 23:23.