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 VCL Delphi Discussion :

Génération dynamique de composants


Sujet :

Composants VCL Delphi

  1. #1
    Membre régulier
    Femme Profil pro
    Inscrit en
    Avril 2007
    Messages
    209
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Suisse

    Informations forums :
    Inscription : Avril 2007
    Messages : 209
    Points : 93
    Points
    93
    Par défaut Génération dynamique de composants
    Bonjour à tous,

    Je rencontre un problème d'affichage lors de la génération dynamique de composants sur une fenêtre Delphi.

    Je génère dynamiquement une liste de composants TPanel placés les uns sous les autres. Ces panels contiennent ensuite des composants (Labels, Mémo, Boutons, ...) toujours identiques. (Les composants et leurs emplacements sont identiques, leur contenu diffère d'une ligne à l'autre)

    Le nombre de panel à générer varie en fonction des cas.

    Lorsque beaucoup de panels doivent être créés, la propriété "TOP" de certains composants devient aléatoire, même si je la fixe à la création.

    J'ai réussi à isoler et reproduire mon problème sur une unité que voici :
    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
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
     
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ExtCtrls, AdvancedPanel;
     
    type
      TComp = Class
      Private
         NoComp : Integer;
         panBase : TPanel;
         mmoInfo : TMemo;
         AOwner : TWinControl;
      Public
         Constructor Create(AOwner_ : TWinControl;
                            NoComp_ : Integer);
         Destructor Destroy;Override;
      End;
     
     
      TForm1 = class(TForm)
        procedure FormCreate(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
      private
        { Déclarations privées }
        Procedure CreerComp;
        Procedure FreeComp;
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    Var
       CompList : TList;
     
    //------------------------------------------------------------------------
    //Classe TComp
    //------------------------------------------------------------------------
     
    Constructor TComp.Create(AOwner_ : TWinControl;
                             NoComp_ : Integer);
    Begin
         AOwner:=AOwner_;
         NoComp:=NoComp_;
     
         panBase:=TPanel.Create(AOwner);
         panBase.Parent:=AOwner;
         //Obligatoire pour que les panels se mettent dans l'ordre de création
         panBase.Align:=alBottom;
         panBase.Align:=alTop;
         panBase.Height:=100;
         panBase.BorderStyle:=Forms.bsSingle;
     
         mmoInfo:=TMemo.Create(PanBase);
         mmoInfo.Parent:=PanBase;
         mmoInfo.Top:=50;
         mmoInfo.Left:=80;
         mmoInfo.Width:=500;
         mmoInfo.Height:=30;
         mmoInfo.Text:='Composant n° : '+IntToStr(NoComp_);
         mmoInfo.Alignment:=taLeftJustify;
         mmoInfo.ReadOnly:=True;
         mmoInfo.BorderStyle:=Forms.bsNone;
         mmoInfo.Color:=clWhite;
         mmoInfo.ScrollBars:=StdCtrls.ssVertical;
    End;
     
     
    Destructor TComp.Destroy;
    Begin
         mmoInfo.Free;
         panBase.Free;
         Inherited;
    End;
     
    //------------------------------------------------------------------------
    //Classe TForm1
    //------------------------------------------------------------------------
     
    Procedure TForm1.CreerComp;
     
    Const NbComp : Integer = 330;
     
    Var
       IComp : Integer;
     
    Begin
         FreeComp;
     
         LockWindowUpdate(Self.Handle);
     
         CompList:=TList.Create;
     
         For IComp:=0 To NbComp Do
         CompList.Add(TComp.Create(Form1,IComp));
     
         LockWindowUpdate(0);
     
         Repaint;
    End;
     
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
         CreerComp;
    end;
     
     
    procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
         FreeComp;
    end;
     
     
    Procedure TForm1.FreeComp;
     
    Var
       I : Integer;
     
    Begin
         If CompList = Nil Then Exit;
     
         For I:=CompList.Count-1 DownTo 0 Do
        (TComp(CompList[I])).Free;
     
         CompList.Clear;
         CompList.Free;
    End;
     
     
    end.
    Vous trouverez ci-joint une image représentant mon problème, ça sera peut être plus facile à comprendre.

    J'ai essayé de mettre un composant "TAdvandedScroller" pour contenir tous les panels, mais j'ai le même problème.

    Encore une information un peu "bizarre", j'ai créer la procédure suivante qui m'affiche les valeur top des panels et mémo créés,

    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
     
    Procedure TForm1.ShowTop;
     
    Var
       IComp : Integer;
       Mess : AnsiString;
     
    Begin
         Mess:='';
     
         For IComp:=320 To 329 Do
         Mess:=Mess+IntToStr(IComp)+' : '+IntToStr((TComp(CompList[IComp])).GetPanTop)+' / '+
               IntToStr((TComp(CompList[IComp])).GetMmoTop)+#13+#10;
     
         ShowMessage(Mess);
    End;
    Si j'appelle cette procédure dans "FormCreate" juste après la création dynamique, les valeurs sont correctes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    320 : 32000 / 50
    321 : 32100 / 50
    322 : 32200 / 50
    323 : 32300 / 50
    324 : 32400 / 50
    325 : 32500 / 50
    326 : 32600 / 50
    327 : 32700 / 50
    328 : 32800 / 50
    329 : 32900 / 50
    Si je la réappelle dans l'évènement "FormShow", les valeurs sont fausses :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    320 : 32000 / 50
    321 : 32100 / 50
    322 : 32200 / 50
    323 : 32300 / 50
    324 : 32400 / 50
    325 : 32500 / 32
    326 : 32534 / -2
    327 : 32534 / -2
    328 : 32534 / -2
    329 : 32534 / -2
    Est-ce que ce problème est connu? y a-t-il un moyen de le résoudre?

    Merci d'avance
    Images attachées Images attachées  

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    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 447
    Points : 24 849
    Points
    24 849
    Par défaut
    Pour ma part, je fais différemment
    selon la situation
    - Peu de Panel en total, l'important c'est dans voir le plus que possible sur une seule page écran (défilement optionnel) : TFlowPanel \ TGridPanel
    - Bcp de Panel, l'important c'est de tous les voir en les défilant : TDBCtrlGrid

    Cas du TFlowPanel \ TGridPanel
    je fais une fenêtre qui servira de panel, je fais autant d'instance de TForm que nécessaire
    tu peux aussi utiliser un TFrame
    C'est bien plus simple pour avoir un Design de panel sympa sans devoir avoir des centaines ligne de code !

    Sous D7, je positionne à la main dans la ScrollBox
    Sous 2007+, j'utilise un TFlowPanel ou TGridPanel qui feront le positionnement parfaitement

    Évidemment, c'est conçu pour un affichage limité, avec peu de panel !
    Ayant fait un affichage de ce genre récemment pour un tableau de bord, ton problème est intéressant !
    L'avantage de TFlowPanel c'est que l'on avoir plusieurs colonnes
    Dans mon monitoring, 300 panels simultanés dépassera la compréhension humaine mais cela pourrait peut-être arriver, faudra que je fasse le test pour voir !

    Car 32600, c'est proche de 2^15 = 32768
    Tu dois arriver à la limite, Windows doit refuser te tel position
    car 32600 + Panel.Heigth dépasse 32767

    Si les données sont directement issues de la Base de Données, utilise plutôt une TDBCtrlGrid qui sera bien plus rapide car ne construit que le nombre de panel visible et simule le défilement !
    On y voit que du feu !

    Tu peux utiliser un TClientDataSet comme source de DB !
    Tu peux l'utiliser comme source du TDBCtrlGrid totalement en mémoire, cela se manipule comme un TTable sur Paradox a peu de chose près
    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

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

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    en effet, personnellement j'aurais écrit ton code comme ceci:

    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
     
    type
      TEditPanel = class(TPanel)
      private
        FMemo: TMemo;
      public
        constructor Create(AOwner: TForm1; Index: Integer);
      end;
     
    constructor TEditPanel.Create(AOwner: TForm1; Index: Integer);
    begin
      inherited Create(AOwner);
      Parent := AOwner;
      SetBounds(0, Index * 100, AOwner.ClientWidth, 100);
     
      FMemo := TMemo.Create(Self);
      FMemo.Parent := Self;
      FMemo.SetBounds(80, 50, 500, 30);
      FMemo.Text := 'Composant n° : ' + IntToStr(Index);
      FMemo.Alignment := taLeftJustify;
      FMemo.ReadOnly := True;
      FMemo.BorderStyle := bsNone;
      FMemo.ScrollBars := ssVertical;
    end;
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
      Index: Integer;
    begin
      for Index := 0 to 329 do
        TEditPanel.Create(Self, Index);
    end;
    mais à partir de 328 la position Top > 32768 dépasse les limites de Windows
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  4. #4
    Membre régulier
    Femme Profil pro
    Inscrit en
    Avril 2007
    Messages
    209
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Suisse

    Informations forums :
    Inscription : Avril 2007
    Messages : 209
    Points : 93
    Points
    93
    Par défaut
    Bonjour à vous deux et d'abord, merci pour vos réponses.

    Concernant l'utilisation d'un TDBCtrlGrid je ne connais pas bien ce composant mais je pense que ça ne sera pas possible dans mon cas car pour chaque ligne de ma base de donnée, je dois créer des labels, des boutons, des TeeChart que je dois dessiner, des mémos, des panels, des pageControl.

    D'après ce que j'ai vu, le TDBCtrlGrid n'accepte pas tous les contrôles. et je dois pouvoir accéder manuellement aux composants, pour faire des calculs ou dessiner les graphiques par exemple. Il me semble que ça n'est pas possible avec TDBCtrlGrid.

    Je vais essayer de voir du coté de flowpanel et gridpanel que je ne connais pas du tout.

    Sinon j'ai trouvé cet article aussi :
    http://stackoverflow.com/questions/1...-of-components

    qui décrit exactement mon problème.
    les 2 dernières solutions ne sont pas possible pour moi :
    - TControl : je dois avoir un contrôle fenêtré pour pouvoir accéder aux boutons et aux graphique et pour qu'il puisse contenir d'autres contrôles
    - TDBCtrlGrid : Même problème que plus haut.

    J'essaie de mettre en place la "Feinte" de la scrollbar" je n'ai pas encore réussi à contourner mon problème. pour l'instant c'est même pire au niveau affichage

    Enfin bon, je poursuit mes recherches.

    Merci encore

  5. #5
    Membre régulier
    Femme Profil pro
    Inscrit en
    Avril 2007
    Messages
    209
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Suisse

    Informations forums :
    Inscription : Avril 2007
    Messages : 209
    Points : 93
    Points
    93
    Par défaut
    Rebonjour,

    Après bien des essais et des échecs, j'ai finalement trouvé une solution qui fonctionne. je suis passée par un composant TAdvStringGrid et dans les cellules de la grilles, je mets mes panels.
    De cette manière, ça fonctionne.

    Pour ceux que ça intéresse :

    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
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
     
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ExtCtrls, AdvancedPanel, dbcgrids, NxScrollControl,
      NxCustomGridControl, NxCustomGrid, NxGrid, NxColumnClasses, NxColumns,
      NxCollection, Grids, AdvObj, BaseGrid, AdvGrid;
     
    type
      TComp = Class
      Private
         NoComp : Integer;
         mmoInfo : TMemo;
      Public
         panBase : TPanel;
         Constructor Create(NoComp_ : Integer);
         Destructor Destroy;Override;
      End;
     
     
      TForm1 = class(TForm)
        AdvStringGrid1: TAdvStringGrid;
        procedure FormCreate(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure AdvStringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
          Rect: TRect; State: TGridDrawState);
      private
        { Déclarations privées }
        Procedure CreerComp;
        Procedure FreeComp;
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    Var
       CompList : TList;
     
    //----------------------------------------------------------------------------------
    //Classe TComp
    //----------------------------------------------------------------------------------
     
    Constructor TComp.Create(NoComp_ : Integer);
     
    Const HeightPan : Integer = 100;
     
    Begin
         NoComp:=NoComp_;
     
         panBase:=TPanel.Create(Form1.AdvStringGrid1);
         panBase.Parent:=Form1.AdvStringGrid1;
         panBase.Height:=Form1.AdvStringGrid1.DefaultRowHeight;
         panBase.Width:=Form1.AdvStringGrid1.DefaultColWidth;
     
         mmoInfo:=TMemo.Create(PanBase);
         mmoInfo.Parent:=PanBase;
         mmoInfo.Top:=50;
         mmoInfo.Left:=80;
         mmoInfo.Width:=300;
         mmoInfo.Height:=30;
         mmoInfo.Text:='Composant n° : '+IntToStr(NoComp_);
         mmoInfo.Alignment:=taLeftJustify;
         mmoInfo.ReadOnly:=True;
         mmoInfo.BorderStyle:=Forms.bsNone;
         mmoInfo.Color:=clWhite;
         mmoInfo.ScrollBars:=StdCtrls.ssVertical;
    End;
     
     
    Destructor TComp.Destroy;
    Begin
         mmoInfo.Free;
         panBase.Free;
         Inherited;
    End;
     
    //------------------------------------------------------------------------------
    //Classe TForm1
    //------------------------------------------------------------------------------
     
    Procedure TForm1.CreerComp;
     
    Const NbComp : Integer = 330;
     
    Var
       IComp : Integer;
     
    Begin
         FreeComp;
     
         AdvStringGrid1.RowCount:=NbComp;
     
         CompList:=TList.Create;
     
         For IComp:=0 To NbComp-1 Do
         Begin
              CompList.Add(TComp.Create(IComp));
              AdvStringGrid1.Objects[0,IComp]:=(TComp(CompList[IComp])).panBase;
     
              If (AdvStringGrid1.TopRow = IComp) Or (AdvStringGrid1.CellRect(0,IComp).Top <> 0) Then
              Begin
                   (TComp(CompList[IComp])).panBase.Left:=AdvStringGrid1.CellRect(0,IComp).Left+2;
                   (TComp(CompList[IComp])).panBase.Top:=AdvStringGrid1.CellRect(0,IComp).Top+2;
                   (TComp(CompList[ICOmp])).panBase.Visible:=True;
              End
              Else (TComp(CompList[ICOmp])).panBase.Visible:=False;
         End;
    End;
     
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
         CreerComp;
    end;
     
     
    procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
         FreeComp;
    end;
     
     
    Procedure TForm1.FreeComp;
     
    Var
       I : Integer;
     
    Begin
         If CompList = Nil Then Exit;
     
         For I:=CompList.Count-1 DownTo 0 Do
        (TComp(CompList[I])).Free;
     
         CompList.Clear;
         CompList.Free;
    End;
     
     
    procedure TForm1.AdvStringGrid1DrawCell(Sender: TObject; ACol,
      ARow: Integer; Rect: TRect; State: TGridDrawState);
     
    Var
       ICOmp : Integer;
     
    begin
         If ACol = 0 Then
         For ICOmp:=0 To CompList.Count-1 Do
         If (AdvStringGrid1.TopRow = IComp) Or (AdvStringGrid1.CellRect(0,IComp).Top <> 0) Then
         Begin
              (TComp(CompList[ICOmp])).panBase.Left:=AdvStringGrid1.CellRect(0,ICOmp).Left+2;
              (TComp(CompList[ICOmp])).panBase.Top:=AdvStringGrid1.CellRect(0,ICOmp).Top+2;
              (TComp(CompList[ICOmp])).panBase.Visible:=True;
         End
         Else (TComp(CompList[ICOmp])).panBase.Visible:=False;
    end;
     
    end.
    Encore merci pour votre aide

    Noémie

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

Discussions similaires

  1. Génération dynamique de composants
    Par merlin1977 dans le forum Composants
    Réponses: 4
    Dernier message: 10/01/2014, 20h55
  2. Réponses: 1
    Dernier message: 25/09/2013, 17h13
  3. Création dynamique de composants et destruction
    Par cpdump dans le forum Composants VCL
    Réponses: 4
    Dernier message: 19/01/2005, 17h57
  4. [SQL*Plus] génération dynamique du fichier de spool
    Par lalystar dans le forum Oracle
    Réponses: 3
    Dernier message: 06/12/2004, 10h44
  5. Réponses: 7
    Dernier message: 22/10/2004, 16h18

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