IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Lazarus Pascal Discussion :

Animation pour patienter [Lazarus]


Sujet :

Lazarus Pascal

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Mai 2018
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2018
    Messages : 18
    Par défaut Animation pour patienter
    J'ai essayé d'insérer une animation pour faire patienter le temps d'un calcul.
    L'animation, à la fréquence gérée par un composant Ttimer se déclenche bien si j'utilise par exemple un Tbutton "Flash" et s'arrête avec un "stop".
    Mais rien ne se passe si je la déclenche en début de boucle et l'arrête en fin de boucle.
    Dans l'exemple je calcule une valeur de pi/4 par la série de Leibnitz : avec 100000000 de termes, ma bécane met 18 secondes (elle est vieille, soyez indulgents), donc une animation pour patienter serait la bienvenue...
    Tous les conseils seront examinés attentivement, merci d'avance
    Voici le code :
    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
    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
    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      inc(start);             //chaque Timer1.interval (ici 1/2 seconde)
      n:=(start mod 2);       //donne la parité de start
      case n of               //alterne les couleurs selon pair ou impair
      0: Shape1.Brush.Color:=clblue;
      1: Shape1.Brush.Color:=clfuchsia;
      end;
    end;
     
    procedure TForm1.chrono(t: word);
    var h,m,s,ms,st : word;
    begin
       decodetime(time,h,m,s,ms);
       case t of
       0: t0:=h*3600+m*60+s;          //heure début du calcul
       1: begin t1:=h*3600+m*60+s;    //heure de fin du calcul
          st:=t1-t0;
          temps.caption:='Durée '+inttostr(st)+' s';
          end;
       end
    end;
     
    procedure TForm1.leibnitz;
    //calcul de Pi/4 par le Développement Limité de ArcTan(1)
    var i,t:longword;
      k:integer;
      w:real;
    begin
      t:=1000000000;  //nombre de termes de la somme
      chrono(0);    //top chrono
    //  start:=0;timer1.enabled:=true;
      w:=1; k:=-1;
      for i:=1 to t do
        begin
         w:=w+k/(2*i+1);
         k:=-k ;
        end;
       labelLeibnitz.caption:='Leibnitz donne Pi/4= '+floattostr(w);
       chrono(1); //Stop chrono
       labelnbdetermes.caption:='avec '+inttostr(t)+' termes';
    //   timer1.enabled:=false;
    end;
     
    procedure TForm1.Button1Click(Sender: TObject); //flash
    begin
      start := 0;
      Timer1.Enabled := True;
    end;
     
    procedure TForm1.Button3Click(Sender: TObject); //stop flash
    begin
      Timer1.Enabled := False;
    end;

  2. #2
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 931
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 931
    Billets dans le blog
    6
    Par défaut
    Bonjour,
    La boucle de calcul ne rend pas la main au système pour lui permettre d'exécuter les affichages.
    Une solution pourrait être de tout inclure dans la procédure de calcul, de la façon suivante (approximative, non testée) :
    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    function TForm1.leibnitz(NbTermes: Longword): Real;
    //calcul de Pi/4 par le Développement Limité de ArcTan(1)
    const
      Intervalle = 100; // pour rafraîchir toutes les 100 ms
    var 
      i: longword;
      k: integer;
      w: real;
      d,f: TDateTime;
    begin
      d := Now; // heure de départ
      w:=1;
      k:=-1;
      for i:=1 to NbTermes do
      begin
        w:=w+k/(2*i+1);
        k:=-k ;
        if NbTermes mod Intervalle = 0 then // pour ne pas appeler l'heure trop souvent
        begin
          f := Now;
          if f >= d + Intervalle/MilliSecondsPerDay then
          begin
            d := d + Intervalle/MilliSecondsPerDay;
            if Shape1.Brush.Color = clblue then
              Shape1.Brush.Color := clfuchsia
            else
              Shape1.Brush.Color := clblue;
     
              // probablement faut-il demander un FillColor et un Repaint de Shape1 ?
     
          end;
        end;
      end;
      Result := w;
    end;
    end;
     
    procedure TForm1.Button1Click(Sender: TObject); 
    var
      debut: TDateTime;
      t: LongWord;
    begin
      Debut := Now;
      t:=1000000000;  //nombre de termes de la somme
      labelLeibnitz.caption:='Leibnitz donne Pi/4= '+floattostr(Leibnitz(t));
      labelnbdetermes.caption:='avec '+inttostr(t)+' termes';
      labelTemps.Caption := 'en ' + Millisecondsbetween(Now, debut).ToString + ' millisecondes'; 
    end;
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  3. #3
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 934
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 934
    Par défaut
    Au moins sous Windows (mais est-ce fondamentalement différent sous Linux ?), autant le timer que l'affichage sont impactés puisque le timer réagit à un message WM_TIMER, la repeinture à WM_PAINT et que la boucle empêche le traitement de la pile de messages.

    C'est typiquement le genre de tâche à déporter dans un thread de travail, on synchronise juste la récupération du résultat.

    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
    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
    type
     
      { TPi4Thread }
     
      TPi4Thread = class(TThread)
      protected
        procedure Execute; override;
        procedure OnTerminate;
      public
        Loops  :LongWord;
        Chrono :QWord;
        Result :double;
      end;
     
      { TForm1 }
     
      TForm1 = class(TForm)
        Button1: TButton;
        labelLeibnitz: TLabel;
        labelnbdetermes: TLabel;
        LabelDuree: TLabel;
        Shape1: TShape;
        Timer1: TTimer;
        procedure Button1Click(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
      private
        FlipFlop :boolean;
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.lfm}
     
    { TPi4Thread }
     
    //calcul de Pi/4 par le Développement Limité de ArcTan(1)
    procedure TPi4Thread.Execute;
    var
      i,t :longword;
      k   :integer;
    begin
      FreeOnTerminate := TRUE;
     
      Loops  := 1000000000;  //nombre de termes de la somme
      Result := 1;
      k      :=-1;
     
      Chrono := GetTickCount64;
     
      for i:=1 to Loops do
      begin
        Result:=Result+k/(2*i+1);
        k:=-k ;
      end;
     
      Chrono := GetTickCount64 -Chrono;
      Synchronize(@OnTerminate);
    end;
     
    procedure TPi4Thread.OnTerminate;
    begin
      Form1.labelLeibnitz.caption   := Format('Leibnitz donne Pi/4 = %.5f', [Result]);
      Form1.labelnbdetermes.caption := Format('avec %d termes', [Loops]);
      Form1.labelDuree.caption      := Format('durée %f s', [Chrono /1000]);
     
      Form1.Button1.Enabled := TRUE;
      Form1.Timer1.Enabled  := FALSE;
    end;
     
    { TForm1 }
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Button1.Enabled := FALSE;
      Timer1.Enabled  := TRUE;
     
      TPi4Thread.Create(FALSE);
    end;
     
    procedure TForm1.Timer1Timer(Sender: TObject);
    const
      Progress :array[boolean] of TColor = (clBlue, clfuchsia);
    begin
      FlipFlop := not FlipFlop;
      Shape1.Brush.Color := Progress[FlipFlop];
    end;

  4. #4
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 644
    Par défaut
    Bonjour,

    Il y a un ordre qui redonne momentanément la main au traitement des messages, c'est Application.ProcessMessages. C'est non seulement utile pour un éventuel timer mais aussi pour garder une certaine réactivité de l'application (réponse aux boutons par exemple).

    Mais ici, je ne suis pas sûr que j'opterais pour un Timer. Avec un simple compteur "j" incrémenté dans le corps de la boucle principale et remis à 0 tous les 10_000_000 de pas provoquant alors l'inversion de couleur, nous obtenons à moindre coût une information de progression.

    Je ne suis pas sûr que l'inversion de k soit la meilleure approche. Si le compilateur ne s'aperçoit pas que k est 1 ou -1, il va faire une division flottante classique c'est à dire une multiplication de k par 1/x.
    On peut espérer éviter la multiplication flottante, donc gagner un peu de temps, en écrivant un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
       w := 1.0;
       i := 1;
       repeat 
          i += 2;
          w := w - 1 / i;
          i += 2;
          w := w + 1 / i;
       until i >= 2000000001;
    Je crois que le nombre de termes est à augmenter de 1 (w non nul initialement).

    Salutations

  5. #5
    Membre chevronné

    Homme Profil pro
    Retraité
    Inscrit en
    Avril 2012
    Messages
    181
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2012
    Messages : 181
    Par défaut
    Bonjour,

    TFPTimer ne serait-il pas adapté à ce genre de situation ? En tout cas c'est celui que j'utilise quand le TTimer est bloqué par le processus en cours...

    bb

  6. #6
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Mai 2018
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2018
    Messages : 18
    Par défaut
    Citation Envoyé par Guesset Voir le message
    Bonjour,

    Il y a un ordre qui redonne momentanément la main au traitement des messages, c'est Application.ProcessMessages. C'est non seulement utile pour un éventuel timer mais aussi pour garder une certaine réactivité de l'application (réponse aux boutons par exemple).

    Mais ici, je ne suis pas sûr que j'opterais pour un Timer. Avec un simple compteur "j" incrémenté dans le corps de la boucle principale et remis à 0 tous les 10_000_000 de pas provoquant alors l'inversion de couleur, nous obtenons à moindre coût une information de progression.

    Je ne suis pas sûr que l'inversion de k soit la meilleure approche. Si le compilateur ne s'aperçoit pas que k est 1 ou -1, il va faire une division flottante classique c'est à dire une multiplication de k par 1/x.
    On peut espérer éviter la multiplication flottante, donc gagner un peu de temps, en écrivant un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
       w := 1.0;
       i := 1;
       repeat 
          i += 2;
          w := w - 1 / i;
          i += 2;
          w := w + 1 / i;
       until i >= 2000000001;
    Je crois que le nombre de termes est à augmenter de 1 (w non nul initialement).

    Salutations
    Merci pour la suggestion.
    Je viens de tester avec affichage tous les 1000 pas de la boucle le nombre de pas restant.
    C'est bon, même si ça va très vite pour cette boucle de calcul, l'affichage du nombre de pas restant défile bien.
    Merci beaucoup, je vais tenter de faire "clignoter" un Tshape, Et puis avec une autre animation contrôlée par un Timer.

    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
    procedure TForm1.GoClick(Sender: TObject);
      var i:longword;  //calcul de Pi/4 par le Développement Limité de ArcTan(1)
      k:integer;
      w:real;
    begin
    //  chrono(0); timer1.enabled:=true;//top chrono
      labeldecompte.caption:=inttostr(t);
      w:=1; k:=-1;
      for i:=1 to t do
        begin
         w:=w+k/(2*i+1);
         k:=-k ;
         if (i mod 1000)=0 then
           begin application.processmessages;
           labeldecompte.caption:=inttostr(t-i);
           end;
        end;
       labeLLeibnitz.caption:='Leibnitz donne Pi/4= '+floattostr(w);
     
    //   chrono(1);timer1.enabled:=false; //Stop chrono
    end;
    Bravo à tous ceux qui ont pris le temps de cogiter la question et de proposer une réponse.

  7. #7
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Mai 2018
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2018
    Messages : 18
    Par défaut avec couleur clignotante
    ça fonctionne aussi avec une alternance de couleur d'une Tshape:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    if (i mod 1000)=0 then
           begin 
             application.processmessages;
             labeldecompte.caption:=inttostr(t-i);
             with Shape1.Brush do
                 if color=clwhite then color:=clblack else color:=clwhite;
           end;
    Mais il faut mettre des lunettes de soleil, sinon l'ellipse clignotante risque de vous tourner épileptique !

  8. #8
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Mai 2018
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2018
    Messages : 18
    Par défaut
    Citation Envoyé par tourlourou Voir le message
    Bonjour,
    La boucle de calcul ne rend pas la main au système pour lui permettre d'exécuter les affichages.
    Une solution pourrait être de tout inclure dans la procédure de calcul, de la façon suivante (approximative, non testée) :
    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    function TForm1.leibnitz(NbTermes: Longword): Real;
    //calcul de Pi/4 par le Développement Limité de ArcTan(1)
    const
      Intervalle = 100; // pour rafraîchir toutes les 100 ms
    var 
      i: longword;
      k: integer;
      w: real;
      d,f: TDateTime;
    begin
      d := Now; // heure de départ
      w:=1;
      k:=-1;
      for i:=1 to NbTermes do
      begin
        w:=w+k/(2*i+1);
        k:=-k ;
        if NbTermes mod Intervalle = 0 then // pour ne pas appeler l'heure trop souvent
        begin
          f := Now;
          if f >= d + Intervalle/MilliSecondsPerDay then
          begin
            d := d + Intervalle/MilliSecondsPerDay;
            if Shape1.Brush.Color = clblue then
              Shape1.Brush.Color := clfuchsia
            else
              Shape1.Brush.Color := clblue;
     
              // probablement faut-il demander un FillColor et un Repaint de Shape1 ?
     
          end;
        end;
      end;
      Result := w;
    end;
    end;
     
    procedure TForm1.Button1Click(Sender: TObject); 
    var
      debut: TDateTime;
      t: LongWord;
    begin
      Debut := Now;
      t:=1000000000;  //nombre de termes de la somme
      labelLeibnitz.caption:='Leibnitz donne Pi/4= '+floattostr(Leibnitz(t));
      labelnbdetermes.caption:='avec '+inttostr(t)+' termes';
      labelTemps.Caption := 'en ' + Millisecondsbetween(Now, debut).ToString + ' millisecondes'; 
    end;
    Bonjour, j'avais déjà envisagé d'inclure un affichage dans la boucle : tous les 1000 pas, afficher combien il reste de pas avant la fin de la boucle. Mais rien n'est affiché tant que la boucle n'est pas achevée... C'est pourquoi je me suis tourné vers l'option Timer. Merci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    for i:=1 to t do
        begin
         w:=w+k/(2*i+1);
         k:=-k ;
         if (i mod 1000)=0 then
           begin
           labeldecompte.caption:=inttostr(t-i);
           end;
        end;

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Deux animations pour patienter
    Par Roland Chastain dans le forum Téléchargez
    Réponses: 13
    Dernier message: 01/09/2016, 09h21
  2. Animation pour patienter
    Par Paul TOTH dans le forum Contribuez
    Réponses: 10
    Dernier message: 09/11/2015, 17h37
  3. [WD16] Animation pour faire patienter l'utilisateur
    Par bombseb dans le forum WinDev
    Réponses: 8
    Dernier message: 14/02/2012, 15h19
  4. Enregistrer une animation pour le web
    Par paradeofphp dans le forum Flash
    Réponses: 1
    Dernier message: 01/08/2006, 14h30
  5. [C#] CF - Affichage du camembert pour patienter
    Par freddyboy dans le forum Windows Forms
    Réponses: 5
    Dernier message: 11/06/2004, 16h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo