ouais
Je n'ai toujours pas réussi à résoudre le problème
quelqu'un aurait t 'il une idée de se que veut dire l'erreur
Tk::Error: Can't locate auto/Tk/Text/WRITE.al in @INC
ou alors une autre idée pour rediriger à la volée la sortie standard vers un widget
Bon, la meilleure solution pour toi et de nous montrer cette procédure de calcul.
Je te conseille de changer la ligneen
Code : Sélectionner tout - Visualiser dans une fenêtre à part syswrite(STDOUT,$text,length($text));Et tous tes soucis seront réglés.
Code : Sélectionner tout - Visualiser dans une fenêtre à part print "$text\n";
Voilà la fameuse procédure dont se sert le programme pour afficher ces résultats et que je ne "peux" modifier:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 sub sysprint { # get argument my $text = $_[0]; # print to STDOUT return syswrite(STDOUT,$text,length($text)); }
Bon, si tu veux pouvoir résoudre ton souci, il faut que tu modifies ta procédure.
1) Comment est elle utilisés dans ton script. Ca m'intrigue de savoir pourquoi elle utilise syswrite plutôt qu'un print normal.
2) Donne nous un exemple de ligne de code appellant cette procédure.
3) Pourquoi tu dis que tu ne peux pas la modifier ?
4) Voici une procédure équivalente à la tienne et tu ne seras plus embêter pour ton Tk
Voilà, et tu pourras maintenant mettre dans ton code Tk ceci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 sub sysprint { # get argument my $text = $_[0]; # print to STDOUT print STDOUT $text; return length($text); }
Tu pourras voir tout en live.
Code : Sélectionner tout - Visualiser dans une fenêtre à part tie *STDOUT, ref $TonWidgetText, $TonWidgetText;
Tiens nous au courant.
Pour répondre à tes questions Djibril:
Voici un exemple d'utilisation de la routine sysprint:
Je n'ai aucune idée de pk ils utilisent un syswrite:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 # Run the BPE server in non-interactive mode # ------------------------------------------ if ( RUNBPE::startMenu('',$menInp,$runbpe,"BPE")) { sysprint ("\n"); sysprint ("BPE-error at ".timstr(localtime(time))."\n"); sysprint ("---------------------------------\n\n"); $$self{ERROR_STATUS} = 1; } else { sysprint ("\n"); sysprint ("BPE finished at ".timstr(localtime(time))."\n"); sysprint ("------------------------------------\n\n"); $$self{ERROR_STATUS} = 0; }
Voici les commentaires de la fonction sysprint:
Je ne "peux" modifier ce perl car il fait partie d'un "ensemble logiciel" utilisé par de nombreuses personnes de mon service ... voilà pourquoi j'aimerais éviter toute modification
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 # -------------------------------------------------------------- # sysprint # Force the print command to STDOUT # Usage : sysprint($text) # Example : sysprint("So long, and thanks for all the fish") # Parameter: text: text string to print # Remark : -Returns number of printed characters #---------------------------------------------------------------
Merci pour ton code.
Bon, la personne qui a écrit ce code s'est pris la tête pour rien.
Si tu modifies la procédure sysprint par mon code, ça te pose un souci? Car cela suffit à faire fonctionner tout le reste de tes programmes. De plus, la fonctionnalité par rapport à la procédure initiale ne change absolument pas car elle fait la même chose.
Maintenant, si tu ne peux vraiment pas ou veux pas, je n'ai pas encore trouvé de solutions, mais je cherche.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 # -------------------------------------------------------------- # sysprint # Force the print command to STDOUT # Usage : sysprint($text) # Example : sysprint("So long, and thanks for all the fish") # Parameter: text: text string to print # Remark : -Returns number of printed characters #--------------------------------------------------------------- sub sysprint { # get argument my $text = $_[0]; # print to STDOUT print STDOUT $text; return length($text); }
Autre solution (http://www.developpez.net/forums/d68...ure-widget-tk/)
Pour ton cas, voici ce que tu peux faire.
Au début de ton script, tu mets ceci
ensuite
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 my $FichierSTDOUT = "SortieSTDOUT.txt"; open( STDOUT, '>', $FichierSTDOUT );
$Scrolled = ton widget text.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 ... my $TailleOctetLu = 0; # Lancement de la procedure toutes les 250 millisecondes my $Id = $mw->repeat( 100, [\&LectureFichierParOctets, $FichierSTDOUT, $Scrolled, \$TailleOctetLu] ); simstations($gest,$dirsave); #Destruction des lancements $Id->cancel(); ... ...
plus loin mettre cette procédure
Et bien évidemment, pense à faire des updates dans ta procédure de calcul
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 #========================================================================= # Procedure pour lire un fichier à partir d'un certain nombre d'octet # Et on affiche le contenu dans un widget #========================================================================= sub LectureFichierParOctets { my ( $Fichier, $RefTextWidget, $RefTailleOctetsFichierLu ) = @_; my $buffer; # Data du fichier à lire my $buffer_size = 1000; # Lecture par 1000 octets open(FIC, '<', $Fichier) or die ("Impossible de lire le fichier $Fichier\n"); # On commence la lecture du fichier depuis le début à partir d'un certain # nombre d'octets seek (FIC, ${$RefTailleOctetsFichierLu} , 0); while( read(FIC,$buffer,$buffer_size) != 0 ) { $RefTextWidget->insert("end", $buffer); } close(FIC); ${$RefTailleOctetsFichierLu} = (stat($Fichier))[7]; # Taille fichier return; }
Et bien merci pour tout ça Djibril,
je teste tout ça et je te tiens au courant.
ça marche merci Djibril pour la fonction repeat (je ne connaissais pas).
Par contre au lieu de faire des update partout dans mon code, j'ai voulu essayer la fonction repeat mais sans succès pour l'instant:
J'ai essayé un truc tout bête du genre:
Je n'ai pas d'erreur signalée, par contre, le rafraichissement du widget ne se fait pas en temps réel mais seulement à la fin.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 my $id = $fen->repeat(100, \&refresh); simstations($gest,$dirsave); #mon calcul $id->cancel(); sub refresh{ $txt->update; }
Pour l'instant je ne vois pas trop pourquoi....
C'est normal que l'update ne se fasse qu'à la fin du calcul. On revient au même souci en ce sens que ton repeat lance normalement la procédure refresh toutes les 100 millisecondes. Mais si ton calcul tourne, plus rien de Perl ne peut tourner pendant ce temps, donc la procédure refresh n'est pas lancée.
C'est pour cela que généralement, on mets des updates dans la procédure qui est censé durer longtemps afin de rafraichir le widget pendant le calcul.
Sinon l'ultime façon de procéder est de faire des processus légers encore appelés threads. Mais c'est très délicat à utiliser en Perl avec des interfaces graphiques, faut bien faire les choses.
J'ai pourrais t'aider à le mettre en place, mais j'aurais besoin de ton script pour le faire proprement.
C'est très sympa Djibril,
Je ne peux poster tout mon code ici donc il faudrait que je t'envoie ça par mail. Je suppose qu'il te faut le code de la GUI et le code du "Main". Je mme documente de mon côté sur les threads.
Merci encore.
Bon, j'ai lu quelques docs sur les threads ce week end et j'avoue que j'ai pas encore tout compris.
Pour l'instant j'ai testé un truc tout bête (dans une callback associée à un bouton) pour dissocier ma GUI de mon calcul:
Effectivement ma GUI n'est plus figée mais l'interpréteur lève 2 erreurs dont la deuxième est fatale et fait tout planter:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 ##test threads my $thread = threads->create ( \&simstations,$gest,$dirsave,$fen); $thread->detach;
Attempt to free non-existent shared string '_TK_RESULT_', Perl interpreter: 0x2aed464 at C:/Perl/lib
/Tk.pm line 252.
Free to wrong pool 2ace4a0 not 235c90 at C:/Perl/lib/Tk/Widget.pm line 98 during global destruction.
Apparemment (de ce que j'ai lu dans les divers forums), cela vient du fait que Perl TK n'est pas thread safe? et qu'il faudrait faire l'appel au thread hors de la callback .... Enfin bref tout cela n'est pas encore très clair pour un débutant comme moi.
Si qqn pouvait m'éclairer de ces lumières?
Je t'ai dis ci dessus que la mise en place des threads avec Tk est pas simple . Il te faut créer un thread avant toute chose. Bref, je suis en train de rédiger un article sur ce sujet pour expliquer sa mise en place.
Hâte d'en prendre connaissance.
Salut,
Tout d'abord bravo Djibril pour ce tutoriel sur la gestion des threads et Perl/tk.
Bon, du coup j'ai tenté de mettre ça en place dans mon application mais je n'arrive pas à partager un objet . C'est à priori normal d'après ce que tu dis dans la partie partage de données.
J'ai du coup une erreur du type:Je vais essayer de me renseigner un peu plus sur le site de l'enstimac.Invalid value for shared scalar at Copie de simuGUI.pl line 1148.
Mais si tu as des suggestions ou quelqu'un d'autre je suis preneur.
Merci d'avance.
Tu ne peux certes pas partager des objets, mais tu peux surement changer ta logique pour faire ce que tu souhaites.
Essaye de nous l'exprimer et on pourra peut être t'aider.
En gros:
L'utilisateur saisit des données (via une GUi) qui vont servir à écrire des fichiers (après calculs).
Ces fichiers étant complexes à générer je les gère en tant qu'objets.
De plus l'utilisateur peut générer autant de fichiers qu'il veut (boucler sur l'interface)
C'est pourquoi j'ai un autre objet (un gestionnaire de fichiers à générer)
que je passe en argument pour lancer les calculs)
C'est ce dernier que je ne parviens pas à partager.
En hyper résumé ça donne ça (je me suis vraiment inspiré de ton tuto)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 my @ArgumentsThread : shared; .... my $gest = GestSta->new(); # Gestionnaire des stations à simuler my $dirsave; # Répertoire ou stocker les données ..... $NomFonction = 'simstations'; @ArgumentsThread = ($gest,$dirsave) ; $TreadTravail = 1;
Ce n'est vraiment pas possible de partager un objet??? car ton mon appli repose la dessus.
Essaye de voir si tu ne peux pas jongler avec shared_clone du module threads::shared :
shared_clone REF
shared_clone takes a reference, and returns a shared version of its argument, performing a deep copy on any non-shared elements. Any shared elements in the argument are used as is (i.e., they are not cloned).
my $cpy = shared_clone({'foo' => [qw/foo bar baz/]});
Object status (i.e., the class an object is blessed into) is also cloned.
my $obj = {'foo' => [qw/foo bar baz/]};
bless($obj, 'Foo');
my $cpy = shared_clone($obj);
print(ref($cpy), "\n"); # Outputs 'Foo'
For cloning empty array or hash refs, the following may also be used:
$var = &share([]); # Same as $var = shared_clone([]);
$var = &share({}); # Same as $var = shared_clone({});
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager