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 :

Fermer correctement une application [Lazarus]


Sujet :

Lazarus Pascal

  1. #1
    Invité
    Invité(e)
    Par défaut Fermer correctement une application
    Bonjour,
    j'essaie de comprendre un petit plus finement le fonctionnement de mes fenêtres.
    Dans un projet, je crée une unique TForm :
    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
    program Project1;
     
    {$mode objfpc}{$H+}
     
    uses
      {$IFDEF UNIX}
      cthreads,
      {$ENDIF}
      {$IFDEF HASAMIGA}
      athreads,
      {$ENDIF}
      Interfaces, // this includes the LCL widgetset
      Forms, unit1
      { you can add units after this };
     
    {$R *.res}
     
    begin
      RequireDerivedFormResource:=True;
      Application.Scaled:=True;
      Application.Initialize;
      Application.CreateForm(TForm1, Form1);
      Application.Run;
    end.
    Cette Form contient un bouton pour fermer le programme.
    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
    unit Unit1;
     
    {$mode objfpc}{$H+}
     
    interface
     
    uses
      Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
     
    type
     
      { TForm1 }
     
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
     
      public
     
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.lfm}
     
    { TForm1 }
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Close;
    //Application.Terminate; ?
    end;
     
    end.
    La méthode Close ferme la fenêtre du projet et le programme semble-t-il. L'ajout de "Application.Terminate" après "Close" est-il redondant dans cette configuration mono-fenêtre ?
    Merci cordialement. Gilles

  2. #2
    Membre éprouvé
    Homme Profil pro
    Chef de projets retraité
    Inscrit en
    Juillet 2011
    Messages
    427
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Chef de projets retraité
    Secteur : Transports

    Informations forums :
    Inscription : Juillet 2011
    Messages : 427
    Points : 1 119
    Points
    1 119
    Par défaut
    Bonjour,

    Pour autant que je sache, CLOSE ferme la fenêtre, SI celle ci est la fenêtre principale de ton programme (la première lancée du projet par Application.CreateForm et qui existe lors de Application.Run) il termine aussi l'application, SINON il ne fait que fermer la fenêtre.

    Cordialement

  3. #3
    Membre extrêmement actif Avatar de Jon Shannow
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Avril 2011
    Messages
    4 419
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable de service informatique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2011
    Messages : 4 419
    Points : 9 923
    Points
    9 923
    Par défaut
    Bonjour,

    De mémoire, il me semble que Application.Terminate permet de passer un "ExitCode" récupérable dans un batch.

    JS
    Au nom du pèze, du fisc et du St Estephe
    Au nom du fric, on baisse son froc...

  4. #4
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    merci pour vos réponses.
    ---
    Je comprends la différence entre un Form.Close et un Application.Terminate.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Close;
      Application.MessageBox(PChar('Message' + LineEnding + 'Le programme va s''arrêter.'),
        'Fin de programme',
        MB_OK or MB_ICONERROR);
      Application.Terminate;
    end;
    Ce petit code le met en évidence.
    ---
    Ce qui m'interpelle est ce qui se passe après le Form.Close si on ne place pas un Application.Terminate :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Close;
    end;
    Dans ce cas (i.e. avec ce code), l'exécutable du projet (lzTerminate.exe) se ferme bien.
    Je lance l'exécutable. Dans le gestionnaire de tâches :
    Nom : lazarus-24051401.png
Affichages : 84
Taille : 20,4 Ko
    Je clique sur le bouton. Le programme se ferme :
    Nom : lazarus-24051402.png
Affichages : 82
Taille : 15,6 Ko

    Dans les faits, je cherche une manière propre de créer une méthode CloseApplication(Sender:TObject; Mess: String) dans une unité séparée (uglobals.pas) qui me permettrait d'être sûr de quitter le programme d'où que j'appelle ce code. Et je ne comprends pas exactement le mécanisme de fermeture du programme.
    J'ai fait une première tentative ainsi :
    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
    unit uglobals;
     
    {$mode ObjFPC}{$H+}
     
    interface
     
    uses
      Classes, SysUtils,
      {added}
      Forms{Tform}, Controls{TwinControls}, Dialogs, LCLType{MessageBox};
     
    procedure CloseApplication(Sender: TObject; Mess: string);
     
    implementation
     
    procedure CloseApplication(Sender: TObject; Mess: string);
    var
      aForm: TForm;
     
      function GetFormCurrent(Sender: TObject): TForm;
      var
        ParentClass: TWinControl;
      begin
        Result := nil;
        if Sender.ClassNameIs('TForm') then
          Result := TForm(Sender)
        else
        begin
          if Sender.ClassNameIs('TControl') then
            begin
            ParentClass := TControl(Sender).Parent;
          while not (ParentClass is TForm) do
            ParentClass := ParentClass.Parent;
          if ParentClass is TForm then
            Result := TForm(ParentClass);
          end;
        end;
       end;
     
    begin
      Application.MessageBox(PChar(Mess + LineEnding + 'Le programme va s''arrêter.'),
        'Fin de programme',
        MB_OK or MB_ICONERROR);
      aForm := GetFormCurrent(Sender);
      if aForm <> Nil then
      aForm.Close;
      Application.Terminate;
    end;
     
    end.
    Le problème que je rencontre est que si je l'appelle à partir d'une procédure de TForm1, l'Application.Terminate n'arrête pas immédiatement la boucle du programme par exemple dans un processus de TForm1 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    procedure TForm1.cbSALARIES_Change(Sender: TObject);
    begin
      CloseApplication(Sender, 'Erreur de transtypage du salarié.');
      Showmessage('Oups');
    end;
    Le showmessage apparait alors que l'Application.Terminate a été déclenché. Donc j'essaie de comprendre le fonctionnement plus finement.
    Dernière modification par Invité ; 14/05/2024 à 14h31.

  5. #5
    Membre éprouvé
    Homme Profil pro
    Chef de projets retraité
    Inscrit en
    Juillet 2011
    Messages
    427
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Chef de projets retraité
    Secteur : Transports

    Informations forums :
    Inscription : Juillet 2011
    Messages : 427
    Points : 1 119
    Points
    1 119
    Par défaut
    Alors de mon point de vue, il te faut appeler "APPLICATION.TERMINATE" (avec un exit code) plutôt que CLOSE Parce que:

    * Il te faudrait passer un pointeur sur l'objet fenêtre principale à ta procédure/fonction pour que tu puisse appeler CLOSE
    * L'évènement ONCLOSEQUERY (appelé par CLOSE) peut dire que la fenêtre NE DOIT PAS être fermée

    Alors que APPLICATION est un objet toujours présent

  6. #6
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par acaumes Voir le message
    Alors de mon point de vue, il te faut appeler "APPLICATION.TERMINATE" (avec un exit code) plutôt que CLOSE Parce que:

    * Il te faudrait passer un pointeur sur l'objet fenêtre principale à ta procédure/fonction pour que tu puisse appeler CLOSE
    * L'évènement ONCLOSEQUERY (appelé par CLOSE) peut dire que la fenêtre NE DOIT PAS être fermée

    Alors que APPLICATION est un objet toujours présent
    Pour le close je n'ai pas de problème (enfin j'espère). Si "l'objet" dépend d'une Form, j'identifie la Form et la méthode CloseApplication déclenche la fermeture de la fenêtre. Ce qui m'interpelle, c'est le fonctionnement (l'incidence) de Application.Terminate dans Application.Run autrement dit l'exécution réelle de Application.Terminate dans la boucle (du thread principal sachant que c'est le seul)... Bon évidemment on peut agir ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    procedure TForm1.cbSALARIES_Change(Sender: TObject);
    begin
    if not LodDataSALARIES() then 
      begin
        CloseApplication(Sender, 'Erreur d''accès au salarié.');
        Exit;
      end;
    end;
    //[Suite du code...]
    Mais cela n'explique pas le fonctionnement et comme j'ai plus de temps maintenant, j'essaye de comprendre un peu mieux.
    Merci. Cordialement. Gilles
    Dernière modification par Invité ; 14/05/2024 à 15h03.

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 741
    Points : 13 285
    Points
    13 285
    Par défaut
    Il ne faut pas chercher trop loin, Application.Terminate fait sortir de la boucle Run en passant Terminated à vrai, rien de plus.

  8. #8
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 815
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 815
    Points : 15 229
    Points
    15 229
    Par défaut
    Yep !

    Citation Envoyé par Jon Shannow Voir le message
    De mémoire, il me semble que Application.Terminate permet de passer un "ExitCode" récupérable dans un batch.
    tutafait !

    Librement inspiré de https://stackoverflow.com/questions/...ms-application, j'ai suivi l'idée ainsi :
    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
    program project1;
     
    {$mode objfpc}{$H+}
     
    uses
      {$IFDEF UNIX}{$IFDEF UseCThreads}
      cthreads,
      {$ENDIF}{$ENDIF}
      Interfaces, // this includes the LCL widgetset
      Forms, Unit1;
     
    {$R *.res}
     
    begin
      ExitCode := 42;
      RequireDerivedFormResource := True;
      Application.Initialize;
      Application.CreateForm(TForm1, Form1);
      Application.Run;
    end.
    Sous Linux, j'ai compilé, exécuté le prog depuis une console, l'ai fermé par la croix et ensuite, dans la console
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    echo $? // commande shell pour récupérer le code de sortie généré par l'appli
    42
    Mais ça fonctionne aussi en GUI avec Close ou avec Application.Terminate :
    Nom : code42.png
Affichages : 72
Taille : 23,6 Ko
    Même message dans les deux cas.
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  9. #9
    Invité
    Invité(e)
    Par défaut
    Merci pour vos réponses.
    Citation Envoyé par Andnotor Voir le message
    Il ne faut pas chercher trop loin, Application.Terminate fait sortir de la boucle Run en passant Terminated à vrai, rien de plus.
    La réponse doit être complétée avec ceci pour expliquer le comportement qui m'interpellait:
    Nom : lazarus-24051405.png
Affichages : 67
Taille : 62,3 Ko

    Cordialement. Gilles
    Images attachées Images attachées  
    Dernière modification par Invité ; 14/05/2024 à 19h17.

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 741
    Points : 13 285
    Points
    13 285
    Par défaut
    Close lance Application.Terminate si c'est la fiche principale mais ça n'a pas d'influence sur la pile d'appel en cours qui ira jusqu'à son terme, ce n'est pas un kill process. Si tu veux l'interrompre il faut toi-même tester Application.Terminated et quitter la(les) procédure(s) le cas échéant.

    Quant aux features, j'interprète ça comme l'initialisation des propriétés et la liaison des événements à la lecture du lfm sans besoin de codage manuel.



    Sinon GetFormCurrent renvoie toujours nil non ? ClassNameIs est le nom réel de la classe, tu n'auras jamais TForm ou TControl mais des dérivés. Utilise is ou InheritsFrom.

  11. #11
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Utilise is ou InheritsFrom.
    Corrigé. Merci.
    Cordialement. Gilles

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

Discussions similaires

  1. Fermer correctement une SurfaceView
    Par herotom99 dans le forum Composants graphiques
    Réponses: 0
    Dernier message: 08/06/2016, 12h23
  2. Comment fermer proprement une application avec map
    Par alex8276 dans le forum Android
    Réponses: 4
    Dernier message: 30/04/2015, 16h09
  3. Réponses: 10
    Dernier message: 25/02/2014, 10h21
  4. Comment décliner correctement une application
    Par Gs_Crash dans le forum Android
    Réponses: 1
    Dernier message: 31/08/2012, 12h51
  5. fermer / quitter une application
    Par distogal dans le forum ASP.NET
    Réponses: 9
    Dernier message: 21/01/2010, 17h11

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