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 :

Purge de composants dynamiques sur formulaire


Sujet :

Lazarus Pascal

  1. #1
    Nouveau membre du Club
    Inscrit en
    Juin 2010
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Juin 2010
    Messages : 44
    Points : 38
    Points
    38
    Par défaut Purge de composants dynamiques sur formulaire
    Bonjour,

    Sur un formulaire, à l'événement ShowForm, je crée dynamiquement des objets TMemo. A l'événement FormClose, je voudrais supprimer définitivement et proprement ces TMemo.

    J'ai commencé à travailler ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure Tf_comment.FormClose(Sender: TObject; var CloseAction: TCloseAction);
    var
        i:integer;
    begin
        for i := 0 to ComponentCount - 1 do
            if Components[i] is TMemo then
                Components[i].Free;
    end;
    Mais je me retrouve avec une erreur au runtime.

    Alors qu'avec ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure Tf_comment.FormClose(Sender: TObject; var CloseAction: TCloseAction);
    var
        i:integer;
    begin
        for i := 0 to ComponentCount - 1 do
            if Components[i] is TMemo then
                showmessage( Components[i].Name );
    end;
    Je n'ai pas d'erreur et j'ai bien x messages avec le nom de mes x TMemo créés ...

    Si vous pouviez jeter un œil et me conseiller.

    D'avance merci.

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 729
    Points : 15 132
    Points
    15 132
    Par défaut
    Bonjour,

    C'est un grand classique : tu supprimes des composants, donc ton ComponentCount évolue (diminue, en l'espèce), donc en bout de boucle tu pointes sur rien si des composants ont été supprimés, chose qui ne se produit pas avec le ShowMessage.

    Faut parcourir la boucle à l'envers : for i := MaxValue downto 0 do....

    PS : pourquoi des guillemets autour de Purge dans le titre ?
    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

  3. #3
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 556
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 556
    Points : 3 929
    Points
    3 929
    Par défaut
    Salut

    La réponse de Jipété est pertinente.

    En invoquant Free sur ton composant, la LCL met à jour la liste des composants en supprimant le poste correspondant d'une part et dans le for, les bornes de l'itération sont évaluées au début de l'itération et non réévaluées pendant l'itération, d'où un déphasage entre la situation initiale et la situation au cours des différentes suppressions.

    Dans ce cas de figure, où les bornes de l'itération peuvent varier, j'aurais préconisé l'emploi d'un while:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    procedure Tf_comment.FormClose(Sender: TObject; var CloseAction: TCloseAction);
    var
      i: integer;
    begin
      i := 0;
      while (i<ComponentCount) do
        if Components[i] is TMemo then
          Components[i].Free
        else
          Inc(i);
    end;
    Fais quand même un test, je ne peux pas le faire.

    Cdlt

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  4. #4
    Nouveau membre du Club
    Inscrit en
    Juin 2010
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Juin 2010
    Messages : 44
    Points : 38
    Points
    38
    Par défaut
    Citation Envoyé par Jipété Voir le message
    ComponentCount évolue (diminue, en l'espèce)
    Comme c'est évident ! Honteux de ne pas avoir trouvé cela avant de poster

    Citation Envoyé par Jipété Voir le message
    Faut parcourir la boucle à l'envers
    Ok, j'avais trouvé un bout de code avec downto et je le trouvais étrange et l'avais remplacé ...

    Du coup je modifie mon code 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
    procedure Tf_comment.FormClose(Sender: TObject; var CloseAction: TCloseAction);
    var
        i:integer;
    begin
        showmessage( 'Composants : '+IntToStr(ComponentCount) );
        for i := ComponentCount - 1 downto 0 do
        begin
            showmessage( 'i='+IntToStr( i )+' nb='+IntToStr(ComponentCount) );
            if Components[i] is TMemo then
            begin
                showmessage( 'Free' );
                Components[i].Free;
            end;
        end;
    end;
    Mais il plante toujours ...
    Sur un formulaire avec un seul TMemo s'affiche 3 messages :
    Citation Envoyé par showmessage
    Composants : 7
    Citation Envoyé par showmessage
    i=6, nb=7
    Citation Envoyé par showmessage
    Free
    Et plantage ... Apparemment sur le Free ...

    Une idée ?

    Citation Envoyé par Jipété Voir le message
    pourquoi des guillemets autour de Purge dans le titre ?
    Je trouvais le mot trop violent

  5. #5
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 556
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 556
    Points : 3 929
    Points
    3 929
    Par défaut
    Peux-tu nous montrer le code de création des composants TMemo (événement OnFormShow) ?

    Cdlt

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  6. #6
    Membre chevronné

    Homme Profil pro
    au repos
    Inscrit en
    Février 2014
    Messages
    429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : au repos

    Informations forums :
    Inscription : Février 2014
    Messages : 429
    Points : 1 884
    Points
    1 884
    Par défaut
    Bonjour,

    ton dernier code (FormClose) ne provoque pas d'erreur chez moi (Win 7).

    Cela dit, il est préférable de coder : (Components[i] as TMemo).Free;

    Remarque :
    Si tu as assigné un Owner à tes Memo, c'est lui qui va se charger de la libération. Donc pas de code "free".
    Le free des TMemo ne s'impose que si ils n'ont pas d'Owner :

    Memo1:= TMemo.Create(nil);

    Cordialement
    Thierry

  7. #7
    Nouveau membre du Club
    Inscrit en
    Juin 2010
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Juin 2010
    Messages : 44
    Points : 38
    Points
    38
    Par défaut
    A partir de la ligne 70 :
    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
    90
    91
    92
    93
    94
    95
    96
    97
    procedure Tf_comment.FormShow(Sender: TObject);
    var
        h_depart, pos_top, w_marge, w_comment, h_total,
          h_comment, w_label, h_label, id_util, nb_comment : integer;
        nom_util:String;
        n_date, n_util: TLabel;
        n_comment: TMemo;
    begin
        // Initialisation des variables de mise en forme
        h_depart := 50;
        pos_top := h_depart;
        nb_comment := 0;
        h_comment := 110;
        w_comment := 400;
        h_label := 20;
        w_marge := 20;
        w_label := 70;
     
        txt_dem.Caption := IntToStr(annee)+' - '+IntToStr(demande);
     
        // Récupération des données dans DBF
        ds_comment.DataSet.Open;
        ds_comment.DataSet.Filtered := false;
        ds_comment.DataSet.Filter:='annee='+IntToStr(annee)+' AND id='+IntToStr(demande);
        ds_comment.DataSet.Filtered := true;
        ds_comment.DataSet.Last;
     
        // Boucle sur les données à afficher
        while not ds_comment.DataSet.BOF do
        begin
          nb_comment := nb_comment + 1;
     
          // TLabel pour date
          n_date := TLabel.Create(self);
          with n_date do
          begin
               name:= 'l_date_'+IntToStr(nb_comment);
               parent:=self;
               Top:=pos_top;
               Left:=w_marge;
               Autosize:=false;
               Wordwrap:=true;
               Width:= w_label;
               Caption:=ds_comment.DataSet.FieldByName('date_heure').AsString;
               Height:= h_label;
          end;
     
          // TLabel pour utilisateur
          n_util := TLabel.Create(self);
          id_util := ds_comment.DataSet.FieldByName('id_user').AsInteger;
          if ds_user.DataSet.Locate('id_user', varArrayOf([id_util]),[]) = true then
             nom_util := ds_user.DataSet.FieldByName('username').AsString
          else
             nom_util := 'Inconnu';
     
          with n_util do
          begin
               name:= 'l_util_'+IntToStr(nb_comment);
               parent:=self;
               Top:=pos_top + h_label;
               Left:=w_marge;
               Autosize:=false;
               Wordwrap:=true;
               Width:=w_label;
               Caption:= nom_util;
               Height:= h_label;
          end;
     
          // TMemo pour commentaires
          n_comment := TMemo.Create(self);
          with n_comment do
          begin
               name:= 'm_memo_'+IntToStr(nb_comment);
               parent:=self;
               Top:=pos_top;
               Left:= w_label + ( 2 * w_marge );
               Width:=w_comment;
               Text:=ds_comment.DataSet.FieldByName('commentair').AsString;
               Height:=h_comment;
               ScrollBars:= ssAutoVertical;
               ReadOnly:=true;
          end;
     
          pos_top := pos_top + h_comment + w_marge;
          ds_comment.DataSet.Prior;
        end;
        ds_comment.DataSet.Close;
     
        // Positionnement de la fenêtre formulaire
        h_total:= h_depart + ( nb_comment * ( h_comment + w_marge ) );
        if h_total > hauteur_ecran then
            height := hauteur_ecran
        else
           height := h_total;
        top := round( ( hauteur_ecran - Height )/2);
        left := largeur_ecran-width;
    end;
    Merci pour le temps passé

  8. #8
    Nouveau membre du Club
    Inscrit en
    Juin 2010
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Juin 2010
    Messages : 44
    Points : 38
    Points
    38
    Par défaut
    Si je teste mon code avec un formulaire qui a plus d'un TMemo attachés, le code ne plante que sur le dernier, mais si je force l'exécution après l'erreur, tous les TMemo sont bien supprimé (?!), puis l'appli se ferme brutalement (!?) à i=0 ...

    Citation Envoyé par ThWilliam
    Si tu as assigné un Owner à tes Memo, c'est lui qui va se charger de la libération.
    A quel moment ? Quel événement ?
    Mon formulaire lui n'est pas créé dynamiquement, il est ouvert et fermé potentiellement plusieurs fois au runtime ... Mauvaise pratique ?
    Sinon je passe toujours self à la création c'est donc le formulaire qui est owner ici.

  9. #9
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 556
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 556
    Points : 3 929
    Points
    3 929
    Par défaut
    Citation Envoyé par ThWilliam Voir le message
    Cela dit, il est préférable de coder : (Components[i] as TMemo).Free;
    Cela ne me semble pas nécessaire, car Free (méthode non virtuelle) invoque Destroy qui est virtuelle donc a priori adaptée à l'objet cible.

    Citation Envoyé par ThWilliam Voir le message
    Si tu as assigné un Owner à tes Memo, c'est lui qui va se charger de la libération. Donc pas de code "Free".
    Le free des TMemo ne s'impose que si ils n'ont pas d'Owner :

    Memo1:= TMemo.Create(nil);
    Oui, j' y ai pensé au début mais je me suis ravisé, car les TMemo ne suivent pas le cycle de vie de la fiche, ils sont instanciés au FormShow et libérés dans le FormClose, ce qui ne suppose pas la libération de la fiche.
    -> Mais, est-ce que la fiche est libérée après la fermeture ?

    Je ne vois pas trop d'où vient ton problème, d'autant que Thierry n'a pas reproduit l'erreur dans son essai. Est-ce le code du FormClose est complet ou as-tu éliminé certaines instruction pour le publier dans cette discussion ?

    As-tu essayé le code que j'avais proposé même si je suis assez pessimiste, vu la bizarrerie de ton problème.

    Cdlt

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  10. #10
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 556
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 556
    Points : 3 929
    Points
    3 929
    Par défaut
    Citation Envoyé par Benzouye Voir le message
    Mon formulaire lui n'est pas créé dynamiquement, il est ouvert et fermé potentiellement plusieurs fois au runtime ... Mauvaise pratique ?
    Sinon je passe toujours self à la création c'est donc le formulaire qui est owner ici.
    Effectivement, cela ne devrait pas poser problème. As-tu d'autres composant TMemo mais qui seraient placés en conception ?

    Une idée serait de déboguer en utilisant les bibliothèques de débogage pour voir à partir d'où cela plante.

    Cdlt

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  11. #11
    Nouveau membre du Club
    Inscrit en
    Juin 2010
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Juin 2010
    Messages : 44
    Points : 38
    Points
    38
    Par défaut
    Le code du formShow est bien complet.

    Citation Envoyé par Benzouye
    Mon formulaire lui n'est pas créé dynamiquement, il est ouvert et fermé potentiellement plusieurs fois au runtime ... Mauvaise pratique ?
    Je fais cette démarche de libération car sinon les TMemo s'empilaient à chaque réouverture du formulaire.
    Dans un premier temps j'ai fais du Hide dans la boucle, mais je me suis dis que Free serait quand même plus pertinent ...

    Citation Envoyé par Benzouye
    Si je teste mon code avec un formulaire qui a plus d'un TMemo attachés, le code ne plante que sur le dernier, mais si je force l'exécution après l'erreur, tous les TMemo sont bien supprimé (?!), puis l'appli se ferme brutalement (!?) à i=0 ...
    ça me déroute complètement ...
    La première erreur m'ouvre le fichier custommemo.inc sur la procédure TCustomMemo.RealSetText ...
    Si je continue l'exécution malgré tout, l'appli se ferme brutalement sans message comme si un Application.Terminate était exécuté ...

  12. #12
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 556
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 556
    Points : 3 929
    Points
    3 929
    Par défaut
    Peux-tu essayer cela ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    procedure Tf_comment.FormClose(Sender: TObject; var CloseAction: TCloseAction);
    var
      i: integer;
    begin
      i := 0;
      while (i<ComponentCount) do
        if Components[i] is TMemo then
          Components[i].Free
        else
          Inc(i);
    end;
    NB : le compteur n'est modifié que si l'on ne supprime pas le composant désigné.

    Cdlt

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  13. #13
    Membre chevronné

    Homme Profil pro
    au repos
    Inscrit en
    Février 2014
    Messages
    429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : au repos

    Informations forums :
    Inscription : Février 2014
    Messages : 429
    Points : 1 884
    Points
    1 884
    Par défaut
    Re-bonjour,

    Evidemment, il faut savoir de quelle Form on parle !

    S'il s'agit de la fiche principale du programme : le FormClose va entrainer le FormDestroy et le programme va s'arrêter.
    S'il s'agit d'une fiche secondaire, mais créée automatiquement : le FormClose ne va pas libérer ses composants, la fiche va simplement devenir invisible, elle ne se libère pas. Donc il est normal, à chaque formShow d'avoir une création supplémentaire de TMemo. Pourquoi créer les memos dans FormShow et non pas dans FormCreate ? Là, on les crée une fois pour toutes.

    Petit code démontrant que les composants créés dynamiquement avec déclaration d'Owner sont bien libérés lors du Destroy de la fiche.

    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
    interface
     
    uses
      Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls;
     
    type
     
      { TForm1 }
     
      TForm1 = class(TForm)
        procedure FormShow(Sender: TObject);
      private
        { private declarations }
      public
        { public declarations }
      end;
     
      TMyPanel = class(TPanel)
        public
          destructor Destroy; override;
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.lfm}
     
    destructor TMyPanel.Destroy;
    begin
       Showmessage('free de mypanel');
       inherited destroy;
    end;
     
    procedure TForm1.FormShow(Sender: TObject);
    begin
       with TMyPanel.Create(self) do
       begin
          Parent:= self;
          Left:= 100;
          Top:= 100;
       end;
    end;
     
    end.
    Cordialement
    Thierry

  14. #14
    Nouveau membre du Club
    Inscrit en
    Juin 2010
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Juin 2010
    Messages : 44
    Points : 38
    Points
    38
    Par défaut
    Citation Envoyé par e-ric Voir le message
    Peux-tu essayer cela ?
    Même punition ...

    Citation Envoyé par e-ric Voir le message
    Une idée serait de déboguer en utilisant les bibliothèques de débogage pour voir à partir d'où cela plante.
    Je ne sais pas de quoi l'on parle ici, mais cela m'intéresse ... Connais-tu un lien vers une ressource pour mettre en place un débogage plus poussé ?
    Directement dans les options de débogage ?

    Citation Envoyé par ThWilliam
    Pourquoi créer les memos dans FormShow et non pas dans FormCreate ?
    Pour expliquer un peu plus. Mon appli permet de créer des demandes d'intervention. Chaque demande peut se voir ajouter des commentaires (date, nom et mémo).
    Depuis la fiche d'une demande (formulaire) un bouton permet de visualiser les commentaires associés (ceci dans le fameux formulaire qui me pose problème).
    Ce formulaire est fixe pour une partie, mais variable dans son contenu. Lorqu'il s'ouvre je recherche les commentaires liés à la demande en cours et les affiches sous forme de mémo (ce type n'est pas imposé d'ailleurs). Lorsque l'on ferme ce formulaire, il me faut le purger en prévision d'une prochaine ouverture avec une autre demande donc d'autres commentaires ...

    Je suis ouvert à critique sur cette organisation, mais je suis vraiment débutant avec FreePascal et Lazarus, en pleine courbe d'apprentissage

  15. #15
    Membre chevronné

    Homme Profil pro
    au repos
    Inscrit en
    Février 2014
    Messages
    429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : au repos

    Informations forums :
    Inscription : Février 2014
    Messages : 429
    Points : 1 884
    Points
    1 884
    Par défaut
    Je n'ai pas testé, mais le problème pourrait être à la création des memos.
    Pour tous tes mémos, tu utilises la même variable (n_comment).
    Voilà, je crois, ce qui devrait désorienter le plus fin des compilateurs.

    Dans ton code, supprime ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    n_comment := TMemo.Create(self);
     with n_comment do
    et remplace par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    with TMemo.Create(self) do

  16. #16
    Nouveau membre du Club
    Inscrit en
    Juin 2010
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Juin 2010
    Messages : 44
    Points : 38
    Points
    38
    Par défaut
    Citation Envoyé par ThWilliam
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    with TMemo.Create(self) do
    Même punition.

    Pour test, j'ai remplacer mes TMemo par des TLabel (ce qui ne me convient pas dans ce contexte) et plus d'erreur ...

    C'est donc un problème avec la libération de TMemo ... non ?

  17. #17
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 556
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 556
    Points : 3 929
    Points
    3 929
    Par défaut
    Peut-être un bug de la LCL, ce ne serait pas le premier, d'autant plus que ton code semble bon.

    Pourquoi n'utilises-tu pas un DBGrid ? de quel type (au sens de la base de données) est le champ commentair ?

    quelle version de Lazarus utilises-tu ?

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  18. #18
    Nouveau membre du Club
    Inscrit en
    Juin 2010
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Juin 2010
    Messages : 44
    Points : 38
    Points
    38
    Par défaut
    Ma colonne DBF est de type ftMemo. Je n'utilise pas de DBGrid car je n'ai pas réussi à afficher correctement un texte long (jusqu'à 12 lignes sur une largeur de 400) dans une cellule ...
    Dans un premier temps j'étais parti là-dessus, sauf qu'en standard le DBGrid affiche "(MEMO)" au lieu du contenu. J'ai réussi à résoudre ce problème en surchargeant DrawColumnCell et PrepareCanvas.
    De plus, en standard le DBGrid n'adapte pas la hauteur des lignes au contenu multilignes. Je n'ai pas réussi à résoudre ce problème ... donc je suis parti sur un formulaire séparé avec des Memo avec scrollbars ...
    Si tu as une astuce pour modifier ligne à ligne la hauteur en fonction du contenu, je suis preneur

    Après le problème avec les TMemo, je suis passé sur des TLabel que je dimensionne en hauteur en fonction du texte contenu et cela fonctionne suffisamment bien ... Mais je suis un peu déçu de ne pas y arriver ...

    Et j'utilise la v1.6RC2 de Lazarus (fpc 3 il me semble) sur win7 64.

  19. #19
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 419
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 419
    Points : 5 818
    Points
    5 818
    Par défaut
    bonsoir,


    le code dans le formShow ce n'est pas forcement on bonne idée ...
    dans ton cas je préfère créer une Méthode du

    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
    90
    91
    92
    93
    94
    95
    96
    Procedure Tf_comment.GenereAndShow(annee,demande : Integer);
    var
      h_depart, pos_top, w_marge, w_comment, h_total,h_comment, w_label, h_label, id_util, nb_comment : integer;
      nom_util:String;
      n_date, n_util: TLabel;
      n_comment: TMemo;
    begin
      // Initialisation des variables de mise en forme
      h_depart := 50;
      pos_top := h_depart;
      nb_comment := 0;
      h_comment := 110;
      w_comment := 400;
      h_label := 20;
      w_marge := 20;
      w_label := 70;
     
      txt_dem.Caption := IntToStr(annee)+' - '+IntToStr(demande);
     
      // Récupération des données dans DBF
      ds_comment.DataSet.Open;
      ds_comment.DataSet.Filtered := false;
      ds_comment.DataSet.Filter:='annee='+IntToStr(annee)+' AND id='+IntToStr(demande);
      ds_comment.DataSet.Filtered := true;
      ds_comment.DataSet.Last;
     
      // Boucle sur les données à afficher
      while not ds_comment.DataSet.BOF do
      begin
        nb_comment := nb_comment + 1;
        // TLabel pour date
        n_date := TLabel.Create(self);
        with n_date do
        begin
          name:= 'l_date_'+IntToStr(nb_comment);
          parent:=self;
          Top:=pos_top;
          Left:=w_marge;
          Autosize:=false;
          Wordwrap:=true;
          Width:= w_label;
          Caption:=ds_comment.DataSet.FieldByName('date_heure').AsString;
          Height:= h_label;
        end;
     
          // TLabel pour utilisateur
        n_util := TLabel.Create(self);
        id_util := ds_comment.DataSet.FieldByName('id_user').AsInteger;
        if ds_user.DataSet.Locate('id_user', varArrayOf([id_util]),[]) = true then
           nom_util := ds_user.DataSet.FieldByName('username').AsString
        else
          nom_util := 'Inconnu';
     
        with n_util do
        begin
          name:= 'l_util_'+IntToStr(nb_comment);
               parent:=self;
               Top:=pos_top + h_label;
               Left:=w_marge;
               Autosize:=false;
               Wordwrap:=true;
               Width:=w_label;
               Caption:= nom_util;
               Height:= h_label;
          end;
     
          // TMemo pour commentaires
          n_comment := TMemo.Create(self);
          with n_comment do
          begin
               name:= 'm_memo_'+IntToStr(nb_comment);
               parent:=self;
               Top:=pos_top;
               Left:= w_label + ( 2 * w_marge );
               Width:=w_comment;
               Text:=ds_comment.DataSet.FieldByName('commentair').AsString;
               Height:=h_comment;
               ScrollBars:= ssAutoVertical;
               ReadOnly:=true;
          end;
     
          pos_top := pos_top + h_comment + w_marge;
          ds_comment.DataSet.Prior;
        end;
        ds_comment.DataSet.Close;
     
        // Positionnement de la fenêtre formulaire
        h_total:= h_depart + ( nb_comment * ( h_comment + w_marge ) );
        if h_total > hauteur_ecran then
            height := hauteur_ecran
        else
           height := h_total;
      top := round( ( hauteur_ecran - Height )/2);
      left := largeur_ecran-width;
      Show;// ou showmodal le cas écheant 
    end;
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  20. #20
    Membre chevronné

    Homme Profil pro
    au repos
    Inscrit en
    Février 2014
    Messages
    429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : au repos

    Informations forums :
    Inscription : Février 2014
    Messages : 429
    Points : 1 884
    Points
    1 884
    Par défaut
    Avec des labels, pas de problèmes ?

    A la différence d'un TLabel, un TMemo est un composant focalisable.
    Serait-ce un problème de libération du memo qui a le focus ?
    En principe, non... mais...

    Si sur ta fiche, tu as un composant focalisable, attribue-lui le focus au début de ta procedure OnClose.
    Sinon, pour tester, tu places un TButton (qui ne sert à rien) et tu lui donnes le focus.

Discussions similaires

  1. problème sur formulaire dynamique
    Par nicolasferraris dans le forum Langage
    Réponses: 4
    Dernier message: 11/03/2009, 09h10
  2. Filtres dynamiques sur formulaire
    Par Sami Xite dans le forum IHM
    Réponses: 4
    Dernier message: 02/05/2008, 19h39
  3. Réponses: 5
    Dernier message: 15/11/2007, 11h52
  4. événement sur composants dynamiques
    Par kirua2150 dans le forum Delphi
    Réponses: 5
    Dernier message: 02/05/2007, 03h33
  5. Evènement sur composant dynamique
    Par Sakapatate dans le forum AWT/Swing
    Réponses: 6
    Dernier message: 22/04/2007, 11h47

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