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

Composants FMX Delphi Discussion :

Comment supprimer une Frame dans une ScrollBox


Sujet :

Composants FMX Delphi

  1. #1
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 569
    Billets dans le blog
    65
    Par défaut Comment supprimer une Frame dans une ScrollBox
    Bonjour,

    En fait, je tente de répercuter une action sur un tframe (créé au runtime)
    n'y arrivant pas, j'ai élaboré un programme test au plus simple

    Nom : Capture.PNG
Affichages : 526
Taille : 29,3 Ko

    l'objectif est de :
    supprimer la frame dont le bouton est utilisé
    faire en sorte qu'il n'y ait pas de vide
    Nom : Capture1.PNG
Affichages : 491
Taille : 7,2 Ko

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    procedure TaFrame.btnRemoveClick(Sender: TObject);
    begin
    Visible:=False;
    Parent:=nil;
    // Free; // ? 
    end;
    sauf que et je ne vois pas comment redessiner le scrollbox
    Comment faire appel à une méthode du parent ?

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 569
    Billets dans le blog
    65
    Par défaut
    Évidemment, une fois posée, j'ai une solution, toutefois si elle s'applique, je ne la trouve pas exceptionnelle.

    1 - J'ai déclaré l'utilisation de l'unité principale dans ma clause uses;
    2 - Ajouté une variable au niveau de ma frame;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public
        { Déclarations publiques }
        p : TMainForm;
    3 - Modifié le code du bouton
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure TaFrame.btnRemoveClick(Sender: TObject);
    begin
    Visible:=False;
    // Parent:=nil; // RemoveObject(self);
    p.redrawscrollbox;
    // Free;
    end;
    4 - Créé cette fameuse méthode
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    procedure TMainForm.redrawscrollbox;
    var i : integer;
    begin
    sp:=0;
    for I := 0 to scrollbox1.ComponentCount-1 do
     begin
      if scrollbox1.Components[i] is TFrame then
       begin
        TFrame(scrollbox1.Components[i]).Position.Y:=sp;
        if TFrame(scrollbox1.Components[i]).Visible then
           sp:=sp+TFrame(scrollbox1.Components[i]).Height;
       end;
     end;
    end;
    Donc, de fait, je joue sur la propriété visible de la Frame, c'est cela qui me fait le plus tiquer (dois-je le préciser ?).
    Reste que je ne sais pas si, dans mon application, cette astuce sera applicable.
    Y a-t-il moyen de faire mieux ?

  3. #3
    Membre expérimenté
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2004
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2004
    Messages : 86
    Par défaut
    Bonjour,
    pour gérer un cas similaire, j'avais simplement utilisé un alignement sur les frames ajoutées dynamiquement :

    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
     
    Unité UDLGFitre
     
    procedure TDLGFiltre.AddSort;
    var myFrameSort : TFrameFilterSort;
    begin
      inc(FIdxFrameSort);
      myFrameSort := TFrameFilterSort.Create(lstsort);
      myFrameSort.parent := lstSort;
      myFrameSort.Name := myFrameSort.Name + IntToStr(FIdxFrameSort);
      myFrameSort.Top := 999;
      myFrameSort.Align := alTop;
      myFrameSort.LstFieldSort := FFieldSortDispo;
      myFrameSort.OnChangeSort := ChangeSort;
      myFrameSort.OnDelete := DeleteSort;
     
      FlstSort.Add(myFrameSort);
    end;
    La position 999 est arbitraire. C'est juste s'assurer de positionner la frame en dessous de la précédente si l'ordre d'affichage des frames est important.

    Ensuite pour la suppression, j'ai ajouté un évènement OnDelete sur la frame :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Unité UFrameFilter
      FOnDelete: TNotifyEvent;
     
     
      property OnDelete:TNotifyEvent read FOnDelete write FOnDelete;
    Sur le bouton de suppression de la frame :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
     
    procedure TFrameFilterSort.btnDeleteClick(Sender: TObject);
    begin
      if Assigned(FOnDelete) then
        OnDelete(Self);
    end;

    Qui est rattaché à la procédure de suppression dans la fenêtre hôte :

    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
     
    Unité UDlgFiltre
     
    procedure TDLGFiltre.DeleteSort(Sender: TObject);
    var i : integer;
    begin  
      for i := FlstSort.Count -1 downto 0 do
      begin
        if FlstSort[i].GUID = TFrameFilterSort(Sender).GUID then
        begin
          FlstSort[i].Free;
          FlstSort.Delete(i);
        end;
      end;
      if FlstSort.Count = 0 then
        AddSort;
    end;


    Je ne sais pas si c'est la meilleure manière de faire, ni si ça répond bien au problème, mais de mon côté ça fonctionne bien.

  4. #4
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 982
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 982
    Par défaut
    Un FlowLayout ne permettrait pas d'empiler automatiquement, je ne connais pas FMX mais c'est ce qui ressemble le plus au FlowPanel

    Et ça doit être pas être loin du Align alTop avec un top plus ou moins adapté pour forcer un ordre en VCL comme le souligne Hermite, parfois l'ordre change, un top différent évite cela ... même si je pense que pour FMX l'ordre dans la liste des controls du parent doit avoir un effet notable aussi puisque tout est dessiné
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 569
    Billets dans le blog
    65
    Par défaut
    Citation Envoyé par Hermite Voir le message
    j'avais simplement utilisé un alignement sur les frames ajoutées dynamiquement
    Oui, l'alignement dans le cadre de ce test eusse put fonctionner
    Citation Envoyé par ShaiLeTroll Voir le message
    Un FlowLayout ne permettrait pas d'empiler automatiquement,
    Effectivement, je n'avais pas pensé à celui-là. Cela aurait pu faire l'affaire pour cet exposé.

    Mais, j'ai montré un essai simplifié à l'extrême qui avait surtout pour but de faire appel à une méthode du parent.

  6. #6
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 982
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 982
    Par défaut
    Si le but c'est d'utiliser le parent, là avec une dépendance explicite, une variable locale aurait fait l'affaire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    procedure TaFrame.btnRemoveClick(Sender: TObject);
    var
      P: TWinControl
    begin
      Visible:=False;
      P := Parent;
      Parent := nil; 
      if P is TMainForm then
        p.RealignFrameInScrollBox;
      // Release; // deprecated ... comment la Frame peut s'auto détruire ... au pire le owner le fera ! 
    end;
    Controls[] au lieu Components[] ... en supposant que FMX fonctionne comme la VCL ... ah non c'est Children si j'en crois la doc !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    procedure TMainForm.RealignFrameInScrollBox;
    var 
      i, sp : integer;
    begin
      sp:=0;
      for I := 0 to scrollbox1.ChildrenCount - 1 do
      begin
        if scrollbox1.Children[i] is TFrame then
        begin
          TFrame(scrollbox1.Children[i]).Position.Y := sp;
          Inc(sp, TFrame(scrollbox1.Children[i]).Height;
        end;
      end;
    end;



    Ensuite, tu peux pousser à la place à un TNotifyEvent pour éviter la dépendance explicite, un couplage plus faible ...
    EDIT : je n'ai pas lu tout ce qu'à écrit Hermite ... pour moi, c'est de loin le plus élégant sans être trop lourd (on pourrait faire une Interface à implémenter type Sink Event mais là c'est plus tordu qu'un simple CallBack)

    Juste c'est la Frame qui a la responsabilité du Parent et non le gestionnaire ainsi par besoin d'un GUID qui a mon avis ne sert à rien, on peut comparer les références d'objets Sender et ceux d'une liste.
    Et le Free même si appelé via CallBack au sein du OnClick du bouton ... libérer un Control en cours d'utilisation ça peut être délicat.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    type
      TaFrame
      ...
      public
        property OnRemove: TNotifyEvent read FOnRemove write FOnRemove;

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure TaFrame.btnRemoveClick(Sender: TObject);
    begin
      Visible:=False;
      Parent := nil; 
      if Assigned(FOnRemove) then
       FOnRemove(Self);
    end;
    Ensuite

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    f.OnRemove := FrameRemoveEventHandler;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure TMainForm.FrameRemoveEventHandler(Sender: Object)
    begin
      RealignFrameInScrollBox;
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut
    j'utilise parfois cette astuce

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    unit MainForm;
     
    interface
     
    uses
      MyFrame;
     
    type
      TMain = class(TForm)
        procedure DoSomething();
      end;
    ...
    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
     
    unit MyFrame;
     
    interface
     
    type
      TMyFrame = class(TFrame)
        procedure test;
      end;
     
    implementation
     
    uses
      MainForm;
     
    type
      TMyFrameHelper = class helper for TMyFrame
        function Main: TMain; inline;
      end;
     
    function TMyFrameHelper.Main: TMain;
    begin
      Assert(Parent is TMain); 
      Result := TMain(Parent);
    end;
     
    procedure TMyFrame.Test;
    begin
      Main.DoSomething();
    end;
    le class helper ajoute une assertion car on s'attend à ce que le parent soit un TMain et ensuite je transtype...comme c'est une function "inline", elle évite simplement de faire un TMain(Parent) partout

    c'est un Helper car on ne peux pas avoir MainForm dans le uses de la partie interface si la frame est déjà dans la partie interface de Main,
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 079
    Par défaut
    Bonsoir,

    Citation Envoyé par SergioMaster Voir le message
    supprimer la frame dont le bouton est utilisé
    faire en sorte qu'il n'y ait pas de vide
    Tu n'es pas allé au bout de ta demande/réflexion : quand tu enlèves une frame, surtout si ce n'est pas la plus en bas, tu vas avoir un trou, ça tu l'as vu, et ensuite tu as deux options : remonter ce qui suit le trou et tu vas te retrouver avec le trou en bas, ou recalculer la hauteur des frames restantes en fonction de leur nombre et de la place disponible.

    J'ai beaucoup souffert sur cette manière de faire qui m'a obligé, au final, à utiliser un TPanel "bouche-trou" aligné en bas et dont la hauteur s'adapte pour faire en sorte que les frames aient toujours une taille identique et soient harmonieusement réparties.
    Bien sûr, jouer sur la hauteur des frames ne peut se faire que si ce qu'elles affichent peut supporter le redimensionnement ; dans mon cas, s'agissant des formes d'onde de morceaux de musique, ça va tout seul.

    Je ne donne pas de code parce qu'il est épouvantablement compliqué, chaque frame étant divisée en deux (canal gauche en haut, trait de séparation et canal droit dessous) et il faut que tout ça soit symétrique et plaisant à l'œil, ce qui oblige à avoir des frames dont la hauteur est impaire, sinon un canal serait plus grand que l'autre, en plus c'est codé en Lazarus.
    Mais si je l'ai fait, d'autres peuvent le faire.

    Pour la première ligne de ta demande, voilà comment je fais, depuis la frame concernée (chaque frame a son bouton) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    procedure Tfrm.sbClosePanelClick(Sender: TObject);
    begin
      if StreamData <> 0 then LibereStreamData(True); // proc locale à l'unité unit4frame, ferme le son, libère le fichier, etc.
      MainForm.CloseMe(Self); // proc dans l'unité principale unit4fiche.
    end;
    Ce CloseMe(Sender: TComponent) dans l'unité principale se chargera avec une boucle de repérer la frame dont le nom lui est passé par "Self" et elle fera ce qu'il faut : libération de la frame concernée puis redimensionnement de la fiche comme expliqué ci-dessus.


    Citation Envoyé par SergioMaster Voir le message
    sauf que et je ne vois pas comment redessiner le scrollbox
    Comment faire appel à une méthode du parent ?
    Pour redessiner, un OnResize ? Limite automatique, selon comment c'est codé. Enfin, j'dis ça j'dis rien, il me semble avoir vu passer le mot "fmx" dont il parait que c'est bien différent de "vcl" et je n'en dirai rien de plus, n'y connaissant rien.

  9. #9
    Membre éprouvé Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 220
    Par défaut
    J'utilise quasiment la même méthode que Hermite avec un TNotifyEvent:

    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
    procedure TForm1.Button1Click(Sender: TObject);
    var
      frm: TMyFrame;
    begin
      Inc(FId);
      frm := TMyFrame.Create(ScrollBox1);
      frm.Name := Format('MyFrame%d', [FId]);
      frm.Parent := ScrollBox1;
      frm.OnDelete := nil;
      frm.Align := alBottom; // pour être ajouté à la fin
      frm.Align := alTop;
    end;
     
    procedure TForm1.DeleteFrame(Sender: TObject);
    begin
      if (Sender is TMyFrame) then
        Sender.Free;
    end;

  10. #10
    Membre Expert
    Avatar de pprem
    Homme Profil pro
    MVP Embarcadero - formateur&développeur Delphi, PHP et JS
    Inscrit en
    Juin 2013
    Messages
    1 876
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : MVP Embarcadero - formateur&développeur Delphi, PHP et JS
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juin 2013
    Messages : 1 876
    Par défaut
    Pour la suppression j'ai maintenant tendance à la soumettre en file d'attente avec un

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Thread.ForceQueue(procedure begin Self.Free; end);
    Pour la demande de recalcul (à faire une fois le cadre supprimé ou masqué), plusieurs autres options :
    - implémentation d'une interface sur la fiche, ce qui te permet de remonter sur les parents de la TFrame jusqu'à un "IQuelqueChose" ou nil
    - création d'un "événement" sur la frame que la fenêtre peut renseigner pour lui dire quoi appeler lorsqu'on supprime la frame. Il suffit d'ajouter une variable "procedure of object" avec ou sans paramètres selon ce que tu veux fournir à la fiche quand tu l'appelles et faire le lien lors de la création de la TFrame.

  11. #11
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut
    j'utilise aussi parfois un TObjectList que je clear dans OnIdle

    https://quality.embarcadero.com/browse/RSP-33676
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

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

Discussions similaires

  1. [VBA] Comment supprimer une ligne entiere dans excel
    Par babouoles dans le forum Macros et VBA Excel
    Réponses: 16
    Dernier message: 06/07/2017, 08h34
  2. Comment supprimer une frame dans une application
    Par AndreDvl dans le forum Tkinter
    Réponses: 1
    Dernier message: 07/08/2007, 22h48
  3. comment supprimer un champ dans une requete ??
    Par loran v2 dans le forum Bases de données
    Réponses: 2
    Dernier message: 24/03/2006, 20h41
  4. [vbexcel]Comment supprimer les doublons dans une combobox?
    Par Mugette dans le forum Macros et VBA Excel
    Réponses: 20
    Dernier message: 24/11/2005, 11h12
  5. [C#] Comment supprimer une ligne dans DataGrid ?
    Par BAUDIER dans le forum ASP.NET
    Réponses: 2
    Dernier message: 20/07/2004, 16h03

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