CREATION DYNAMIQUE DE CONTROLES

cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 - 26 déc. 2005 à 14:27
 Utilisateur anonyme - 21 août 2007 à 16:01
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/35260-creation-dynamique-de-controles

Utilisateur anonyme
21 août 2007 à 16:01
j'ai besion de savoir comment modifier la couleur d'un composant dynamique creer par exemple j'ai utiliser votre méthode pour creer un bitbtn mais j'arrive pas a modifier leur coleur merci pour votre exemple. pour plus de contact voici mon Email: etudiant_mail@yahoo.fr
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
27 déc. 2005 à 20:33
Pour la gestion des évènements OnDragOver, OnMouseDown and so on, les déclarations sont en Protected au niveau de TControl. Ce n'est qu'au niveau du composant directement utilisable que la portée est déclarée Published.Il est donc normal que le compilateur n'accepte pas que tu affectes un pointeur de méthode à ce niveau.

Pour les composants TDbEdit, TDbMemo ou TDbCheckbox, il n'y a pas d'ancêtre commun au delà de TWinControl (si tu as le poster de la hiérarchie de la VCL, jettes-y un oeil). Autant dire que c'est quasiment impossible de réaliser un code commun au traitement des différents cas de figure (composants "simples" et composants orientés données).
Icebird Messages postés 10 Date d'inscription lundi 14 novembre 2005 Statut Membre Dernière intervention 27 décembre 2005
27 déc. 2005 à 10:04
J'ai un souci pour centraliser mon code de création avec quelques proptiétés. Il n'y a aucun problème pour toutes les propriétés communes aux TControl, mais, malgré le fait qu'ils apparaissent dans l'aide dans la liste d'evenements d'un TControl, impossible d'affecter les OnDragOver et OnMouseDown, j'ai une erreur de compilation.

Dans le même genre, je crée des DBEdit, DBMemo et DBCheckBox. A chaque fois je doit définir leur propriété DataField et DataSource. J'ai voulu centraliser çà au lieu d'avoir un cas particulier pour chaque type de composant DB, mais rien à faire, ils n'ont pas de composant parent avec ces propriétés en commun, et je me retrouve obligé de faire une série de "if ... is ... then".
Bref, je ne réussit à avoir en commun que les propriétés les plus basiques: top, left, parent, tag et name.
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
26 déc. 2005 à 20:31
Pour lire les propriétés Caption, il faut charger le projet dans Delphi, n'est-ce pas ?
Or, la lecture d'un code source devrait suffire pour comprendre quelles actions sont réalisées par les différents composants !
Il est également bien venu d'appliquer un minimum de conventions comme préfixer ses boutons par "btn", les TEdit par "ed", etc.
C'est un conseil que je te donne, après tu en fais ce que tu veux...

Pour le TComponentlist, je crois me souvenir qu'il existait déjà sous Delphi 4.

Pour info : les métaclasses sont également appelées références de classe. D'ailleurs, en consultant l'aide en ligne, tu trouveras un exemple de code exploitant le principe des métaclasses.

Que Delphi soit avec toi. ;o)
Icebird Messages postés 10 Date d'inscription lundi 14 novembre 2005 Statut Membre Dernière intervention 27 décembre 2005
26 déc. 2005 à 16:16
Génial! Merci beaucoup, il me manquait en effets deux/trois trucs et je butait dessus depuis un moment:

TComponentList: C'est récent non? Je me suis remit à Delphi depuis très peu de temps après 5 ans d'absence, et à l'époque il me semble que le tableau dynamique était la seule solution. Maintenant que je sais qu'il existe, je vais explorer un peu ce TComponentList avec grand plaisir =)

MetaClasses: Encore quelque chose que j'ignorais, et le point sur lequel je butais. Je vais de ce pas approfondir, je sens que çà va bien m'aider.

Nommage: oui, un peu de fainéantise de ma part, je l'avoue, mais en même temps il n'y a pas 36k boutons, et leurs captions sont assez explicites.
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
26 déc. 2005 à 14:27
Je reste convaincu que :
1- l'utilisation d'un TComponentList serait plus judicieux et efficace qu'un tableau dynamique (très coûteux en temps de traitement et moins facile à utiliser lorsqu'il s'agit de détruire un composant et non pas la totalité)

2- l'utilisation des métaclasses permettrait de réduire significativement le code source en n'ayant qu'une seule fonction à maintenir. Comme les composants visuels héritent tous de la classe TControl, c'est d'autant plus facile.

3- nommer les composants utilisés dans le code n'est assurément pas une perte de temps (et ça aide les débutants à comprendre ce qu'est censé faire une procédure)

Voici ma proposition pour un résultat identique :
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Contnrs, StdCtrls;

type
TForm1 = class(TForm)
btnCreateLabel: TButton;
btnCreateMemo: TButton;
btnCreateButton: TButton;
btnCreateEdit: TButton;
GroupBox1: TGroupBox;
btnDeleteCreatedControls: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btnCreateLabelClick(Sender: TObject);
procedure btnCreateMemoClick(Sender: TObject);
procedure btnCreateButtonClick(Sender: TObject);
procedure btnCreateEditClick(Sender: TObject);
procedure btnDeleteCreatedControlsClick(Sender: TObject);
private
FComponentList: TComponentList;
{Contient l'index du dernier composant créé à l'exécution.
Sert au nommage des composants et à éviter les conflits de noms dans le cas de suppression partielle d'objets dans la liste}
LastCreatedIndex: integer;
{Ajoute un contrôle de la classe TControlClass, avec comme parent AParent et avec les coordonnées ATop et ALeft}
function AddComponent(AControlClass: TControlClass; AParent: TWinControl; ATop, ALeft: integer): TControl;
public

end;

var
Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
{Création de la iste de composants en lui passant True, ceci pour qu'elle détruise elle-même les composants sur lesquels elle pointe lors de sa propre destruction}
FComponentList := TComponentList.Create(True);

LastCreatedIndex := 0;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
FComponentList.Free;
end;

function TForm1.AddComponent(AControlClass: TControlClass;
AParent: TWinControl; ATop, ALeft: integer): TControl;
begin
Result := AControlClass.Create(self as TComponent);
Result.Parent := AParent;
Result.Top := ATop;
Result.Left := ALeft;
{Ne pas se baser sur l'index de FComponentList car ce dernier
redistribue les index en cas de suppression d'éléments. Ceci aboutirait à des conflits de noms de composants}
Result.Name := Format('Compo%d', [LastCreatedIndex]);
FComponentList.Add(Result);
inc(LastCreatedIndex);
end;

procedure TForm1.btnCreateLabelClick(Sender: TObject);
var
AControl: TControl;
begin
AControl := AddComponent(TLabel, self, Random(ClientHeight), Random(ClientWidth));
TLabel(AControl).Caption := TLabel(AControl).Name;
end;

procedure TForm1.btnCreateMemoClick(Sender: TObject);
begin
AddComponent(TMemo, self, Random(ClientHeight), Random(ClientWidth));
end;

procedure TForm1.btnCreateButtonClick(Sender: TObject);
begin
AddComponent(TButton, GroupBox1, Random(GroupBox1.ClientHeight), Random(GroupBox1.ClientWidth));
end;

procedure TForm1.btnCreateEditClick(Sender: TObject);
begin
AddComponent(TEdit, GroupBox1, Random(GroupBox1.ClientHeight), Random(GroupBox1.ClientWidth));
end;

procedure TForm1.btnDeleteCreatedControlsClick(Sender: TObject);
begin
{Suppression de tous les composants créés à l'exécution}
FComponentList.Clear;
//facultatif !
LastCreatedIndex := 0;
end;

end.

Le code de création dynamique de composants est ainsi centralisé et plus facile à maintenir.
L'utilisation de la métaclasse TControlClass permet de créer bon nombre de composants visuels puisqu'elle est l'ancêtre immédiat des branches TGraphicControl et TWinControl dans la hiérarchie des classes.

L'utilisation d'un membre privé FComponentList:TComponentList n'est pas une obligation en soi (pas plus qu'un tableau dynamique) puisque la fiche est propriétaire des composants que l'on crée. Toutefois, cette technique permet de pouvoir repérer les composants créés à l'exécution et uniquement ceux-ci et, donc, les détruire facilement par un appel à la méthode Clear de FComponentList.
Mon objectif était aussi de vous faire découvrir l'utilisation simplissime de la classe TComponentList.

En espérant que j'ai été assez clair...
Rejoignez-nous