ThWilliam
Messages postés418Date d'inscriptionmardi 3 janvier 2006StatutMembreDernière intervention26 novembre 2013
-
19 avril 2006 à 14:18
ThWilliam
Messages postés418Date d'inscriptionmardi 3 janvier 2006StatutMembreDernière intervention26 novembre 2013
-
20 avril 2006 à 23:12
Bonjour à tous.
Les variables de type Record ne pouvant pas être publiées, je crée une classe dérivée de TPersistent :
TMyClass = class(TPersistent)
private
FVar1: integer;
FVar2: TColor;
...
published
property Var1: integer read FVar1 write FVar1;
property Var2: TColor read FVar2 write FVar2;
...
end;
Dans le constructeur de TMyCompo: FMyProp:= TMyClass.Create;
Cela marche parfaitement.
Mais si je modifie la propriété MyProp :
property MyProp: TMyClass read FMyProp write SetMyProp;
procedure TMyCompo.SetMyProp (AValue: TMyClass);
begin
FMyProp.Assign(AValue);
Invalidate;
end;
...alors l'assignation des valeurs se fait toujours bien, mais la procedure SetMyProp n'est pas appelée --> pas d'invalidate.
Je n'ai pas trouvé de solution. Comment faire ?
Merci d'avance.
florenth
Messages postés1023Date d'inscriptiondimanche 1 août 2004StatutMembreDernière intervention17 août 20083 19 avril 2006 à 14:52
C'est normal, car ce n'est pas ton objet TmyClass que tu changes mais ses propriétés. tu dois sonc définir des Setter pour TMyClass.
Bref, pas simple à expliquer, je reprend ton exemple, tu vas mieux comprendre :
<hr size= "2" width="100%">TMyCompo = class ;
TMyCompo = class (TGraphicControl)
private FMyProp: TMyClass;
published property MyProp: TMyClass read FMyProp;
end;
implementation
constructor TMyClass.Create(AOwner: TMyCompo);
begin inherited; { en fait, on garde la référence du composant pour
pouvoir appeler sa méthode Invalidate(). }
FOwner : = AOwner;
end;
procedure TMyClass.
Changed;
begin { hop, on demande au compo de se redessiner. }
FOwner.Invalidate;
end;
procedure TMyClass.
SetVar1(Value: Integer);
begin FVar1 := Value;
Changed; // signalement de changement.
end ;
procedure TMyClass.
SetVar2(Value: TColor);
begin
FVar2 : = Value;
Changed; // signalement de changement.
end;
<hr size="2" width="100%">
Et voila !
Bon là, j'ai enlevé la possibilité de changer TMyCompo.MyProp mais tu peux le remettre si tu veux.
Gestion de mémoire:
- Le TMyClass ne doit PAS libérer le TMyCompo dans le destructeur.
- Le TMyCompo DOIT libérer le TMyclass dans son destructeur.
/!\: Attention aux fuites de mémoire sinon ! ;-)
Il faut faire attention à ne pas transmetre 'nil' au constructeur de l'objet sinon plantage assuré.
La toute première ligne de code est une déclaration avancée. C'est nécessaire car TMyclass utilise TMyCompo et inversement.
Si tu ne comprends pas cette ligne, c'est pas bien grave, fais juste un petit tour dans l'aide de delphi
J'espère que ça va t'aider.
N'hésite pas si tu as des difficultés à reposer une quesiton
@ ++
Florent
Si tu ne te plantes pas ......
tu ne pousseras jamais
Cirec
Messages postés3833Date d'inscriptionvendredi 23 juillet 2004StatutModérateurDernière intervention18 septembre 202250 19 avril 2006 à 15:11
Salut,
procedure TMyClass.
Changed;
begin { hop, on demande au compo de se redessiner. }
If Assigned(FOwner) Then // re-hop, pas de problème si 'Nil' est transmis au constructeur ;-)
florenth
Messages postés1023Date d'inscriptiondimanche 1 août 2004StatutMembreDernière intervention17 août 20083 19 avril 2006 à 15:22
@ Cirec: c'est pour cela que j'ai précisé "Il faut faire attention à ne pas transmetre 'nil' au constructeur de l'objet sinon plantage assuré"
Mais entre nous, ça n'as pas d'interet.
Je préfererais même l'utilisation de la procedure Assert() qui elle, génère une reerur facilement repèrable.
Parce qu'avec ton test Cirec, si on transmet nil su constructeur, on verra rien et on peut passer des heures à vérifier ou ça me***.
Là, pour cette taille de projet, j'imagine que c'estpas trop dur mais j'ai des unités qui dépassent les 2500 lignes et là, va trouver ton problème si ça marche pas comme il faut mais que ça génère aucune exception !!
++
Si tu ne te plantes pas ......
tu ne pousseras jamais
ThWilliam
Messages postés418Date d'inscriptionmardi 3 janvier 2006StatutMembreDernière intervention26 novembre 20134 19 avril 2006 à 21:10
Salut Florent,
Salut Cirec,
Que c'est génial d'apprendre !
Je n'avais pas pensé à la solution de redéfinir le constructeur avec paramètre AOwner.
Pour que TMyClass puisse être employé avec différents composants, j'ai pensé aux modifs suivantes :
FOwner: TComponent;
constructor TMyClass.Create(AOwner: TComponent);
et dans procedure TMyClass.Changed :
with FOwner as TControl do Invalidate;
Cela marche, mais y-at-il une objection ?
Question sur utilisation des resources : est-ce que le fait de créer une classe pour regouper des propriétés en mode conception bouffe beaucoup plus de ressources que le fait d'écrire ces propriétés dans le composant lui-même ?
Grand merci à vous 2.
A +
Thierry
Vous n’avez pas trouvé la réponse que vous recherchez ?
florenth
Messages postés1023Date d'inscriptiondimanche 1 août 2004StatutMembreDernière intervention17 août 20083 19 avril 2006 à 21:25
Pour ta première suggestion: c'est même une très bonne idée ! Par contre, déclare FOwner comme Tcontrol puisque Invalidate() n'est disponible qu'a partir de ce niveau là.
Si tu ne te plantes pas ......
tu ne pousseras jamais
florenth
Messages postés1023Date d'inscriptiondimanche 1 août 2004StatutMembreDernière intervention17 août 20083 19 avril 2006 à 22:13
"Question sur utilisation des resources : est-ce que le fait de créer
une classe pour regouper des propriétés en mode conception bouffe
beaucoup plus de ressources que le fait d'écrire ces propriétés dans le
composant lui-même ? "
=> J'en ai strictement aucune idée. Ce que je peux te dire par contre, c'est que, comme tout, il ne faut pas en abuser.
De toutes façons, la référence d'une classe est un pointeur donc 4 octets. Comme tu en a un pour le conteneur et un pour le contenu, on peux dire qu'il y aurait environ 8 octets de plus.
Ce qui n'est rien quand on sait que 8 octets correspondent à 3 pixels d'un bitmap (en 24bit/pixel) et que les mémoires des ordi dépassent les 128 Mo soit 128000000 Octets. Alors un de plus, un de moins ...
PS: un Ko (kilo-Octet) est égal à 1000 Octets et non 1024 (2^10). C'est une nouvelle norme qui date d'a peu près un an et du coup, tout le monde confond
Si tu ne te plantes pas ......
tu ne pousseras jamais
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202235 20 avril 2006 à 16:04
voila comment doivent etre tes objets :
(au passage, ça tiens seulement plus de place dans le code ... au final l'utilisation est hyper simplifiée et surtout plus souple et puissante qu'une simple structure record)
constructor TMyClass.Create(Control : TControl);
begin
inherited create;
{code --vvvv-- down}
fControl := Control;
fVar1 := 0;
fVar2 := 0;
end;
destructor TMyClass.Destroy;
begin
{code --^^^^-- up}
inherited destroy;
end;
procedure TMyClass.fSetInt(Index : integer; Val : integer);
begin
case Index of
0: if Val <> fVar1 then begin
fVar1 := Val;
Change;
end;
1: if Val <> fVar2 then begin
fVar2 := Val;
Change;
end;
end;
end;
procedure TMyClasse.Change;
begin
if Assigned(fOnChange) then fOnChange(Self);
end;
procedure TColorBytes.AssignTo(Dest: TPersistent);
begin
if Dest is TMyClass then
with TMyClass(Dest) do begin
fVar1 := Self.fVar1;
fVar2 := Self.fVar2;
Change;
end
else
inherited AssignTo(Dest);
end;
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202235 20 avril 2006 à 16:10
ps : invalidate ne sert qu'a redessiner le control ... donc totalement inutile dans un composant non visuel.
si il s'agit d'un composant visuel et qu'il est necessaire de
rafraichir l'affichage quand la propriété MyProp est modifiée, il faut
placer le invalidate ici :
procedure TMyCompo.DoMyPropChange(Sender : TObject);
begin
invalidate;
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202235 20 avril 2006 à 16:12
d'ailleur petit rappel de l'aide delphi a propos de invalidate :
Utilisez Invalidate quand la totalité du contrôle doit être dessinée.Si plusieurs zones d'un contrôle doivent être redessinées,Invalidate provoque le réaffichage de toute la fenêtre en une seule passe,pour éviter les instabilités provoquées par les redessins redondants.Les performances ne sont pas dégradées par plusieurs appels d'Invalidate avant que le contrôle ne soit effectivement redessiné.
florenth
Messages postés1023Date d'inscriptiondimanche 1 août 2004StatutMembreDernière intervention17 août 20083 20 avril 2006 à 18:58
Voila un exemple de la puissance des classes.
Les evenements, c'est mieux dans certains cas. Pour celui-ci, il est vrai que j'ai hésité. Mais ça dépend de l'avenir de la classe: a voir.
Mais par contre, f0xi: si tu crée un evenement, cela ne sert plus a rien d'avoir une reférence à un TControl dans TMyClass.
Serais-ce un oubli de ta part ?
Et puis c'est quoi ce TColorBytes ici : TColorBytes.AssignTo(Dest: TPersistent);
lol
Encore un lapsus j'imagine.
Par contre, dna scette même procédure AssignTo(), tu ne réassigne pas toutes les propriétés: l'évenement par exemple. Et dans ce las là, c'est quand même bien dommage !
Allez, a +
Florent
Si tu ne te plantes pas ......
tu ne pousseras jamais
ThWilliam
Messages postés418Date d'inscriptionmardi 3 janvier 2006StatutMembreDernière intervention26 novembre 20134 20 avril 2006 à 23:12
Salut f0xi,
J'ai un peu de mal avec :
property MyProp : TMyClass read FmyProp write FSetMyProp;
Avec déclaration : property MyProp : TMyClass read FmyProp write FMyProp;
alors je comprends :
en modifiant la valeur de Var1 (p.ex)
--> appel de TMyClass.FSetInt
qui appelle TMyClass.Change
qui appelle l'événement OnChange,
c.à.d. l'exécution de TMyCompo.DoMyPropChange.
Mais avec la procédure FSetMyProp , je ne comprends pas comment se fait l'assignation de valeur (je ne vois pas l'appel à TMyClass.FSetInt).
Bref, je suis dans le brouillard...
Quoiqu'il en soit, plein de choses intéressantes pour moi dans ton code.