Identification d'un composant Parent

Résolu
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 - 20 mai 2013 à 09:35
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 - 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
A voir également:

26 réponses

cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
21 mai 2013 à 11:04
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
3
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
21 mai 2013 à 13:07
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]
3
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
21 mai 2013 à 15:57
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]
3
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
23 mai 2013 à 13:04
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]
3

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
korgis Messages postés 420 Date d'inscription samedi 17 mai 2003 Statut Membre Dernière intervention 6 mai 2019 17
23 mai 2013 à 20:40
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;
3
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
23 mai 2013 à 23:21
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]
3
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
24 mai 2013 à 15:55
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]
3
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
21 mai 2013 à 12:24
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
0
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
21 mai 2013 à 12:34
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
0
korgis Messages postés 420 Date d'inscription samedi 17 mai 2003 Statut Membre Dernière intervention 6 mai 2019 17
21 mai 2013 à 13:57
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;
0
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
21 mai 2013 à 14:44
Salut,

Et pourquoi ne pas surcharger le Constructor de ton compos :
Constructor TQuest.Create(AOwner: TComponent; AParent: TWidgetControl);
0
korgis Messages postés 420 Date d'inscription samedi 17 mai 2003 Statut Membre Dernière intervention 6 mai 2019 17
21 mai 2013 à 15:59
@Caribensila : sur le OnCreate, ça plante.
Il semble que le parent ne puisse être attribué qu'après la création du composant.
0
korgis Messages postés 420 Date d'inscription samedi 17 mai 2003 Statut Membre Dernière intervention 6 mai 2019 17
21 mai 2013 à 16:02
@cirec : si dans "SetParent" je vérifie "if Assigned(AParent) then", ben...
Il est pas assigné, le parent. Et il se passe rien.
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
21 mai 2013 à 16:16
@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]
0
korgis Messages postés 420 Date d'inscription samedi 17 mai 2003 Statut Membre Dernière intervention 6 mai 2019 17
21 mai 2013 à 17:16
@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...
0
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
21 mai 2013 à 19:29
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
0
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
23 mai 2013 à 12:06
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
0
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
23 mai 2013 à 17:43
@ 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
0
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
23 mai 2013 à 21:14
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
0
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
23 mai 2013 à 23:29
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
0
Rejoignez-nous