Identification d'un composant Parent [Résolu]

cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 20 mai 2013 à 09:35 - Dernière réponse : cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention
- 24 mai 2013 à 16:10
Bonjour,

J'écrit un composant et j'ai besoin d'identifier son composant Parent au moment ou je le dépose quelque part.

Déclaration du composant:

type
  TQuest = class(TCustomControl)
  Private 
  ...  
  _ParentCtrl  : TComponentName;
  public
  ...
  Constructor Create(AOwner: TComponent);override;
  ...
End;


Pour Dimensionner correctement le composant au moment de l'exécution (au moment du dépot il a une surface par défaut de 200 x 300), j'identifie le composant dès le create:

Constructor TQuest.Create(AOwner : TComponent);
Begin
  inherited Create(AOwner);
  inherited Width := 200;
  inherited Height:= 300;
  Parent       := AOwner as TWinControl;
  _ParentCtrl  := Parent.Controls[0].Name;
...

End;


Questions :

1. Est-ce l'affectation de Parent := est correcte?
Si je fais showmessage(inttostr(Parent.Width)), il ne semble pas me donner la bonne largeur du composant parent;

2. Je récupère bien le nom du Parent dans
_ParentCtrl, mais j'ai utilisé un indice 0 arbitraire. Est-ce ça sera toujours vrai? A priori mon composant ne peux avoir qu'un seul parent, il est donc à l'indice zéro?

Merci

Jean_Jean
Afficher la suite 

Votre réponse

26 réponses

Meilleure réponse
cs_cantador 4996 Messages postés dimanche 26 février 2006Date d'inscription 27 mars 2018 Dernière intervention - 21 mai 2013 à 11:04
3
Merci
Bonjour,

_ParentCtrl  := Parent.Controls[0].Name;


on voit tout de suite que ça ne peut pas fonctionner..
il faudrait boucler sur l'ensemble des indices.

mais reformulons..

tu souhaites déposer un composant et si le conteneur est repéré alors
ton composant prend automatiquement Width := 200 et Height:= 300;

c'est bien ça ?

cantador

Merci cs_cantador 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 99 internautes ce mois-ci

Commenter la réponse de cs_cantador
Meilleure réponse
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 21 mai 2013 à 13:07
3
Merci
Salut,

[quote=Jean_Jean]Parent := := AOwner as TWinControl;

me donne Form1 comme Parent, ce qui est faux./quote

c'est juste

il ne faut pas confondre Owner et Parent

le meilleur moyen, à mon avis, c'est de surcharger la procédure SetParent ... ainsi
dès que le parent est affecté ou changé tu en es informé

...
  protected
    procedure SetParent(AParent: TWinControl); override;
...

procedure TQuest.SetParent(AParent: TWinControl);
begin
  inherited SetParent(AParent);
  _ParentCtrl := AParent.Name;
end;

[hr]@+Cirec
[hr]

Merci Cirec 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 99 internautes ce mois-ci

Commenter la réponse de Cirec
Meilleure réponse
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 21 mai 2013 à 15:57
3
Merci
Salut à tous,
tiens ... Monsieur Caribensila ... ça faisait longtemps
ça fait plaisir de voir que les anciens passent encore de temps en temps

[quote=Korgis]Chez moi, la surcharge de SetParent plante au moment de la fermeture du form... /quote

Si tu fais le même teste que dans ton OnPaint c'est normal !!!!

dans ce cas il faufrait l'écrire comme ceci:
procedure TQuest.SetParent(AParent: TWinControl);
begin
  inherited;
  if Assigned(AParent) then
    Caption := aParent.Name;
end;

en fait il faudrait toujours tester si AParent est assigné dans le cas où l'on veut récupérer son nom.


[quote=sinon mon ami Caribensila]Et pourquoi ne pas surcharger le Constructor de ton compos/quote

c'est une solution mais elle ne fonctionnera pas en design time. Il me semble que c'est ce que Jean_Jean souhaite:
[quote=Jean_Jean]J'écrit un composant et j'ai besoin d'identifier son composant Parent au moment ou je le dépose quelque part. /quote

[hr]@+Cirec
[hr]

Merci Cirec 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 99 internautes ce mois-ci

Commenter la réponse de Cirec
Meilleure réponse
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 23 mai 2013 à 13:04
3
Merci
re,

je crois que t'as pas bien saisi le fonctionnement du code !!!

la méthode SetParent ne doit pas être appelée par tes soins et surtout pas dans le OnCreate. Il suffit de la surcharger et quand la VCL ou l'utilisateur définit un parent tu en es avisé.
procedure TQuest.SetParent(AParent: TWinControl);
begin
  inherited SetParent(AParent);
  if Assigned(AParent) then
    // ici ta procédure qui utilise le Parent
end;


ce petit bout de code va réagir comme un évènement ... dès que la valeur de Parent change il lancera ta procédure

sinon publier Parent n'est pas utile ...
cette propriété est déjà publique ça suffit amplement.


[hr]@+Cirec
[hr]

Merci Cirec 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 99 internautes ce mois-ci

Commenter la réponse de Cirec
Meilleure réponse
korgis 424 Messages postés samedi 17 mai 2003Date d'inscription 4 août 2018 Dernière intervention - 23 mai 2013 à 20:40
3
Merci
Mais dès que j'utilise ces propriétés dans le create ça plante

Pourquoi ne pas tout simplement les utiliser dans la procedure SetParent ?
Attention : sans oublier de vérifier que le Parent est bien assigné !
procedure TQuest.SetParent(Val : TWinControl);
begin
  inherited SetParent(Val);
  if Assigned(Val) then
  begin
    showmessage(Val.Name+' => '+ inttostr(val.Width)+' x '+inttostr(Val.Height));
    // tes calculs en fonction du Parent
  end.
end;

Merci korgis 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 99 internautes ce mois-ci

Commenter la réponse de korgis
Meilleure réponse
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 23 mai 2013 à 23:21
3
Merci
re

dans le OnCreate c'est tout simplement pas possible ... pour la simple et bonne raison qu'à ce moment le parent n'est pas encore affecté!

que ce soit la VCL ou toi qui crée le composant c'est pareil:

aQuest := TQuest.Create(Self); // <-- appel du constructeur

aQuest.Parent := Form1; // le Parent est toujours définit après le OnCreate 
il y a un ordre d'appel et de ce fait il est impossible d'utiliser le Parent dans le OnCreate.


[hr]@+Cirec
[hr]

Merci Cirec 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 99 internautes ce mois-ci

Commenter la réponse de Cirec
Meilleure réponse
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 24 mai 2013 à 15:55
3
Merci
oui alors non ...

les évènements de type TNotifyEvent sont là pour donner à
l'utilisateur du composant (le dev) la possibilité de réagir à
un évènement précis (OnPaint OnCreate etc. etc.)

Les Messages Windows (WM_PAINT ... etc.) ne sont pas d'une plus grande utilité
ici ... la plupart des messages sont envoyés par Windows aux applications
ce qui permet de gérer l'affichage à l'écran (par exemple) et les composants recevant ces messages peuvent déclencher un évènement en retour (OnPaint)

mais pour toi pas besoin de ça:

TQuest = class(TWinControl)
private
  FZoomState: TZoomState;
  procedure SetZoomState(aValue: TZoomState);
published
  property ZoomState: TZoomState read FZoomState write SetZoomState;
end;

procedure TQuest.SetZoomState(aValue: TZoomState);
begin
  if aValue <> FZoomState then
  begin
    FZoomState := aValue;
    Invalidate; // ici le composant est redessiné 
  end;
end;



ceci devrait suffire ...


[hr]@+Cirec
[hr]

Merci Cirec 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 99 internautes ce mois-ci

Commenter la réponse de Cirec
cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 21 mai 2013 à 12:24
0
Merci
Yo cantador!

Oui, c'est bien le problème d'identifier le contener sur lequel je dépose mon compo!

J'ai pris l'exemple de 200 x 300 au départ dans la phase conception. Donc si je repère le bon parent, je pourrai déterminer les dimension du contener Parent du composant qui pourra prendre un format quelconque avec les moduf de l'utilisateur...

Dans les exemples de compo, à aucun moment je ne vois ce problème de détermination du composant parent. Sinon, après, je peux faire Parent.Width et Parent.height

Je bosse dessus. ça va pas être triste, gros tutorial en vue compte tenu de toutes les questions que je pose... ça pourra aider d'autres...

Bien à toi

Jean_Jean
Commenter la réponse de cs_Jean_Jean
cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 21 mai 2013 à 12:34
0
Merci
J'ai oublié de préciser

Parent := := AOwner as TWinControl;

me donne Form1 comme Parent, ce qui est faux. J'ai un TPanel comme Parent!


Jean_Jean
Commenter la réponse de cs_Jean_Jean
korgis 424 Messages postés samedi 17 mai 2003Date d'inscription 4 août 2018 Dernière intervention - 21 mai 2013 à 13:57
0
Merci
Salut,

Sujet intéressant...
Chez moi, la surcharge de SetParent plante au moment de la fermeture du form...
Par contre, en surchargeant OnPaint, c'est nickel :
protected    
    procedure Paint; override;

procedure TQuest.Paint;
begin
  inherited Paint;
  Caption := Parent.Name; // <- test
end;
Commenter la réponse de korgis
Caribensila 2684 Messages postés jeudi 15 janvier 2004Date d'inscription 26 juillet 2018 Dernière intervention - 21 mai 2013 à 14:44
0
Merci
Salut,

Et pourquoi ne pas surcharger le Constructor de ton compos :
Constructor TQuest.Create(AOwner: TComponent; AParent: TWidgetControl);
Commenter la réponse de Caribensila
korgis 424 Messages postés samedi 17 mai 2003Date d'inscription 4 août 2018 Dernière intervention - 21 mai 2013 à 15:59
0
Merci
@Caribensila : sur le OnCreate, ça plante.
Il semble que le parent ne puisse être attribué qu'après la création du composant.
Commenter la réponse de korgis
korgis 424 Messages postés samedi 17 mai 2003Date d'inscription 4 août 2018 Dernière intervention - 21 mai 2013 à 16:02
0
Merci
@cirec : si dans "SetParent" je vérifie "if Assigned(AParent) then", ben...
Il est pas assigné, le parent. Et il se passe rien.
Commenter la réponse de korgis
Cirec 4231 Messages postés vendredi 23 juillet 2004Date d'inscription 3 août 2018 Dernière intervention - 21 mai 2013 à 16:16
0
Merci
@korgis:

je comprends pas bien où tu fais une erreur ... j'ai testé le code et il fonctionne parfaitement !!!

  TQuest = class(TEdit)
  protected
    procedure SetParent(AParent: TWinControl); override;
  end;
implementation
{ TQuest }

procedure TQuest.SetParent(AParent: TWinControl);
begin
  inherited SetParent(AParent);
  if Assigned(AParent) then
    Caption := aParent.Name;
end;


et pour tester:
procedure TfrmNumPad.FormCreate(Sender: TObject);
begin
  with TQuest.Create(Self) do
    Parent := TabSheet2;
end;


et le TEdit apparait sur le Parent choisit
et affiche son nom !


[hr]@+Cirec
[hr]
Commenter la réponse de Cirec
korgis 424 Messages postés samedi 17 mai 2003Date d'inscription 4 août 2018 Dernière intervention - 21 mai 2013 à 17:16
0
Merci
@korgis:

je comprends pas bien où tu fais une erreur ... j'ai testé le code et il fonctionne parfaitement !!!


Exact. Je viens de tester ton code, pas de problème.
J'ai dû merder quelque part dans mes tests...
Commenter la réponse de korgis
cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 21 mai 2013 à 19:29
0
Merci
Oulà!
Merci à tous de vos réponses!
Je n'ai pas le temps d'y répondre précisément ce soir, car je suis en déplacement demain toute la journée. Mais Jeudi je teste...

@korgis:
Justement, je ne veux pas utiliser paint. Les dimensions du conteneur sont déterminées une fois pour toutes dans le create et utilisé en interne par le composant. Du moins à ce niveau de reflexion. Je n'ai pas déterminé la necessité pour le programmeur d'utiliser la propriété parent dans l'inspecteur d'objet car j'aurai beaucoup d'autres propriétés à afficher...

@ Caribensila: salut vieux loup!
Je me posai la question sur ton écriture! Mais j'ai peur qu'une surcharge du create hérité ne provoque des comportements dont je ne suis pas sûr de maitriser par la suite. C'est mon compo principal qui sera au coeur d'autres sous-composants...
En plus Cirec, le maestro a répondu à ma question. Il faut que ça fonctionne quand j'ai csDesigning à true.

@Cirec:
Toujours aussi efficace dans tes réponses, un vrai bonheur...
Mais j'ai pas le temps de tester ce soir.
En lisant vos réponses, je me demandai s'il fallait que je déclare la propriété Parent dans published.
En début d'après-midi, j'avais essayé en ajoutant également GetParent ou FParent inherited en lecture mais ça plante à la compile car il dit que GetParent ne fait pas parti de la class ancêtre.

J'ai besoin de lire la valeur du Parent, pas de la fixer par le Setter puisque je ne la connaît pas. ça serait dommage d'obliger le programmeur de fixer lui-même la valeur du composant Parent!

Bon faut que je prépare là!

Merci à tous!

A Jeudi



Jean_Jean
Commenter la réponse de cs_Jean_Jean
cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 23 mai 2013 à 12:06
0
Merci
Me revoilà!

J'ai du mal à m'en sortir de cette affaire! Je me demande si c'est possible...

Puisqu'il semble difficile de capter le nom du parent qui va recevoir mon composant, j'ai eu l'idée de procéder à l'inverse:

Parcourir tous les composants de la Fiche principale donnée apparemment par défaut par le Owner dans le create et :

1) Identifier le nom de mon composant
2) Voir parmi la liste des composants celui qui a pour enfant mon composant car il semble plus facile d'aller en descendant qu'en remontant

Or j'ai un souci dans ma boucle qui identifie pourtant bien mon composant (étape 1). Voici le code:

Constructor TQuest.Create(AOwner : TComponent);
Begin
  inherited Create(AOwner);
  inherited Width := 200;
  inherited Height:= 300;
  if (csDesigning in ComponentState) then
      SetParent(f_ParentOf(AOwner));
...
end;


La fonction qui devra identifier le Parent qui qui pour l'instant n'identifie que son propre nom :

Function TQuest.f_ParentOf(AChildren : TComponent): TWinControl;
  Var ii : integer;
Begin
  Result := AChildren as TWinControl; // Par defaut
  For ii := 0 to AChildren.ComponentCount - 1 do begin
    if AChildren.Components[ii] Is TQuest then
    begin
     try
      Result := TQuest(AChildren.Components[ii]).Parent;
      if not Assigned(result) then 
      begin
        showmessage('Non assigné');
        Exit;
      end;
     Except
     end;
    end;
  end;
End;



TWinControl(AChildren.Components[ii]).Name me donne le nom de mon composant mais pourtant il ne semble pas assigné;

Si bien que si j'écris en sortie de fonction

Result.name, ça plante!

Jean_Jean
Commenter la réponse de cs_Jean_Jean
cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 23 mai 2013 à 17:43
0
Merci
@ Cirec
Oui, il y a des subtilités qui m'échappent!

mais en fait, j'avais bien compris au début quant tu as donné ta solution que tu as donné dès le départ que je viens de reessayer.

Dans le setter qui est appelé effectivement dès le dépot du composant, je peux voir le nom, et les dimensions du composant sans problème:

procedure TQuest.SetParent(Val : TWinControl);
begin
  inherited SetParent(Val);
  showmessage(Val.Name+' => '+ inttostr(val.Width)+' x '+inttostr(Val.Height));
end;


Mais dès que j'utilise ces propriétés dans le create ça plante. C'est pour ça que j'ai cru qu'il me manquait quelque chose. Car je voudrais utiliser ces propriétés pour certains calculs préliminaires avant exécution et modifications du programmeur.

J'ai bidoullé au début dans les déclarations mais ikl ne faut pas compte tenu de l'héritage...

Donc maintenant ma question est de savoir si on peut utiliser ces propriétés dans le create.

Dans le cas contraire, qu'elle serait la méthode utilisée avant le paint.

Sinon bien sûr, je peux faire dans le paint un if csDesigning pour affecter les valeurs mais ça se répète à chaque modif en conception et c'est un test qu'on pourrait éviter de répéter...

Procedure TQuest.Paint;
Begin
  inherited paint;
  if (csDesigning in ComponentState)then    showmessage(Parent.Name+' => '+ inttostr(Parent.Width)+' x '+inttostr(Parent.Height));



Jean_Jean
Commenter la réponse de cs_Jean_Jean
cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 23 mai 2013 à 21:14
0
Merci
Oui, je crois que je vais faire l'initialisation de mon composant dans une procédure spécifique appéllée dans le Setter.

Dans le créate, j'ai pas trouvé...

Merci à vous tous!

procedure TQuest.SetParent(Val : TWinControl);
begin
  inherited SetParent(Val);
  if Assigned(Val) and (csDesigning in  
     ComponentState) and
     not (csLoading in ComponentState) and
     not (csReading in ComponentState) then
  begin
    showmessage(Val.Name+' => '+ inttostr(val.Width)+' x '+inttostr(Val.Height));
  end;
end;



Jean_Jean
Commenter la réponse de cs_Jean_Jean
cs_Jean_Jean 639 Messages postés dimanche 13 août 2006Date d'inscription 5 mai 2016 Dernière intervention - 23 mai 2013 à 23:29
0
Merci
Merci Cirec!
Oui, ça parait logique
J'avais espéré.
ça me complique un peu pour la suite, mais bon.
J'étais en train de regarder justement, quel évènement je pourrai utiliser (le OnRizize peutêtre) ou qu'elle procédure héritée, je pourrai utiliser juste après le créate
Ou encore une autre piste; le ComponentState csloading...




Jean_Jean
Commenter la réponse de cs_Jean_Jean

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.