Un controle refuse d'être représenté par une variable [Résolu]

Signaler
Messages postés
132
Date d'inscription
dimanche 29 octobre 2006
Statut
Membre
Dernière intervention
24 août 2020
-
 fredelem -
Bonjour,

J'ai un programme qui commence par:

   
Var
    MonControle; TControl;

Begin
   Moncontrole:=Label1;
   Moncontrole.Name:='Etiquette1';


Tout ça marche très bien.

Mais si, au lieu de vouloir changer le nom de mon controle, je veux changer la procédure associée à un évènement (le Click par exemple), et si j'écris:

   MonControle.OnClick:=Nil;


je n'ai pas de message d'erreur mais ma ligne n'est pas prise en compte, la procédure associée à OnCLick reste la même.

Quelqu'un connaitrait-il une ruse pour contourner ça ?

Merci d'avance.

Fred
--

12 réponses

Messages postés
6
Date d'inscription
mardi 31 août 2004
Statut
Membre
Dernière intervention
5 juin 2014

Bonjour

Une "ruse" qui fonctionne très bien dans une de mes applications :


Type :
Sender = TObject;

var
MyKontrol: sender;

implementation
procedure Form1.XYZ(sender:Tobject);
begin ..{par ex. caption:='Cliqué...'}.. end;

procedure Form1.formcreate;
......
With (MyKontrol as TLabel) do
onclick:=XYZ;
......

Suggestion d'un pur amateur....
Bonne continuation.
Messages postés
420
Date d'inscription
samedi 17 mai 2003
Statut
Membre
Dernière intervention
6 mai 2019
16
Salut,

Pas de message d'erreur du compilateur ? Étonnant...

TControl est une classe abstraite, son évènement OnClick est protégé. Il n'est publié que par ses descendants.

Pour un TLabel, il te faut donc faire :

(MonControle as TLabel).OnClick := nil;

ou bien

TLabel(MonControle).OnClick := nil;
Messages postés
132
Date d'inscription
dimanche 29 octobre 2006
Statut
Membre
Dernière intervention
24 août 2020
2
Merci à tous les deux pour ces réponses. Elles marchent toutes les deux (elles sont d'ailleurs à peu près équivalentes).

Dans la réponse de GLBX, je me demande si la création d'un type "sender" est bien utile. Après l'avoir lue, j'ai tout simplement écrit (MonControle As TLabel).OnClick comme dans la réponse 1 de Korgis et ça a marché ! C'est super !

Mais je veux faire la même chose avec d'autres composants qui ne seront pas tous des labels. J'utilise une procédure qui ressemble beaucoup à la procédure XYZ de l'exemple de GLBX. Est-il possible d'ajouter un paramètre dans cette procédure pour indiquer le type de mon contrôle ? Par exemple, dans certains cas, écrire XYZ(sender,TLabel) et dans d'autres XYZ(sender, TButton) ?
J'ai essayé d'écrire:
 Procedure Xyz(sender:Tobject; Sontype:TType);
Mais le type TType n'est pas reconnu! Des idées ?



--
Messages postés
4719
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
1 février 2021
14
bonjour,

On peut utiliser FindComponent() qui permet de détecter la classe du composant s'il existe et lui affecter le OnClick.
Messages postés
132
Date d'inscription
dimanche 29 octobre 2006
Statut
Membre
Dernière intervention
24 août 2020
2
Ok, merci, je vais essayer cette piste.

Je pensais avoir trouvé la solution avec le mot Classtype car si j'écris:

Showmessage(Label1.Classtype.classname);

j'obtiens "TLabel"

Je pensais donc que je pouvais écrire:

(MonComposant as Moncomposant.Classtype).OnClick:=Nil;


Mais là encore, ça ne marche pas: pas de message d'erreur mais l'ordre n'est pas exécuté, le OnCLick reste ce qu'il était.

Je vais donc essayer ce que tu me proposes.
Je suppose qu'il me faudra écrire Findcomponent(Moncomposant), ce qui va me renvoyer le composant Label1. Comment avoir son type à partir de ça ?

--
Messages postés
273
Date d'inscription
samedi 13 juin 2009
Statut
Membre
Dernière intervention
18 avril 2015
10
Salut,
Si tu fais (MonComposant as tLabel).OnClick:=Nil;
çà marche (j'ai essayé). Comme les ClassType n'ont pas tous des evenement onclick, il doit se perdre. Avec mon vieux D5 je ne peux pas compiler avec "as classtype(MonComposant)".
Qq1 sait ?

solilog



--
Messages postés
132
Date d'inscription
dimanche 29 octobre 2006
Statut
Membre
Dernière intervention
24 août 2020
2
Merci Solilog mais j'ai déjà essayé ça, rien à faire, on ne peut pas transtyper avec Classtype.

J'ai fini par comprendre l'idée de Cantador et j'ai essayé de définir la procédure par
  PROCEDURE Xyz(Nom_du_controle);
  With Findcomponent(Nom_du_controle) do
        OnClick:=Nil; 


Comme ça, je n'ai pas d'erreur (car c'est la Form qui prend pour elle le OnClick:=Nil) mais si j'enlève le With et si j'écris

  Findcomponent('Label1').Onclick:=Nil;


j'ai bien mon message d'erreur "Onclick connais pas" car bien sûr, au moment de la compilation, on ne sait pas quel est le type de Label1. Le compilateur se dit que c'est peut-être un type Bevel qui n'a pas de OnClick et il ne veut pas prendre de risque.

Je crois que pour cette dernière partie, on ne trouvera pas mais pour la première partie, c'est gagné et c'est déjà beau. Merci à tous.

Fred

--
Messages postés
132
Date d'inscription
dimanche 29 octobre 2006
Statut
Membre
Dernière intervention
24 août 2020
2
J'ai quand même finalement trouvé une solution qui marche mais est-ce une solution, une astuce, une ruse ou une combine ?

Je pense que c'est une méprisable combine mais je vous la livre tout de même: j'utilise TLabel(MonControle) quel que soit le type de mon contrôle et ça marche impeccable avec un bouton, une groupbox, un memo, un edit, un radiobutton, une checkbox et même avec un bevel. Je suis d'ailleurs surpris par la complaisance du bevel qui ne déclenche pas de message d'erreur si je lui attribue une couleur ou un OnClick, lui qui n'a aucune de ces deux propriétés.

Et voilà, on y est arrivé. Je peux déclarer "Problème résolu".

--
Messages postés
263
Date d'inscription
lundi 27 octobre 2003
Statut
Membre
Dernière intervention
28 avril 2021
13
Salut
exemple (pas testé) pour un label et je pense facilement exploitable pour faire la procedure XYZ
var
FComponent : TComponent;
begin
FComponent := FindComponent('Label1');
if FComponent <> nil then
if FComponent.ClassNameIs('TLabel') then
if Assigned(TLabel(FComponent).OnClick) then
TLabel(FComponent).OnClick := nil
else
TLabel(FComponent).OnClick := Label1Click;
end;
Pour ce qui est du bevel je suppose qu'il hérite de TControl et que si on essaye un truc du genre
TLabel(FindComponent('Bevel1')).OnClick := Label1Click;
et que l'on clic sur le bevel, on lance la procédure associée (A tester) et hop un OnClick sur le bevel :p
@+
Messages postés
132
Date d'inscription
dimanche 29 octobre 2006
Statut
Membre
Dernière intervention
24 août 2020
2
Merci pour cette aide de dernière minute. Je vois ce que tu veux faire: n'appliquer le OnClick:=Nil que si une procedure lui est déjà assignée. Ce n'est pas une mauvaise idée mais dans mon rpogramme, ce n'est pas indispensable. Par contre, je ne vois pas pourquoi, dans le cas contraire, tu veux lui assigne la procedure Label1Click.
Mais, ça me fait penser que je devrais, avant de dire "OnClick:=Nil" mettre en mémoire la procedure Label1Click si elle existe et la rétablir lorsque j'ai fini le travail qui m'a forcé à l'écarter temporairement.

Le bevel me surprend: si j'écris, en dehors de tout programme
TLabel(Bevel1).Color:=ClRed,
je n'ai aucun message d'erreur ni à la compilation ni à l'exécution et la form ne devient pas rouge.
Par contre, bien sûr,
TBevel(Label1).Color:=ClRed
provoque un message d'erreur à la compilation.

Comme tu le supposes, si j'écris:
TLabel(Bevel1).OnClick:=Label1OnClick;
la procedure Label1OnClick(sender) se limitant à
Showmessage(TObject(sender.name));
ça marche, le bevel réagit au click et affiche son nom.

Nous avons inventé une façon d'ajouter des évènements à des composants qui en manquent !!!!

--
Messages postés
3825
Date d'inscription
vendredi 23 juillet 2004
Statut
Modérateur
Dernière intervention
1 février 2021
42
Rien d'étonnant ...

TControl --> TGraphicControl --> TBevel
TControl --> TGraphicControl --> TCustomLabel -- > TLabel

et TControl possède de base ces propriétés elles ne sont juste pas utilisées dans les descendants tel que TBevel:

extrait de TControl:
    property ActionLink: TControlActionLink read FActionLink write FActionLink;
    property AutoSize: Boolean read FAutoSize write SetAutoSize default False;
    property Caption: TCaption read GetText write SetText stored IsCaptionStored;
    property DesktopFont: Boolean read FDesktopFont write SetDesktopFont default False;
    property DragKind: TDragKind read FDragKind write FDragKind default dkDrag;
    property DragCursor: TCursor read FDragCursor write FDragCursor default crDrag;
    property DragMode: TDragMode read GetDragMode write SetDragMode default dmManual;
    property IsControl: Boolean read FIsControl write FIsControl;
    property MouseCapture: Boolean read GetMouseCapture write SetMouseCapture;
    property ParentBiDiMode: Boolean read FParentBiDiMode write SetParentBiDiMode default True;
    property ParentColor: Boolean read FParentColor write SetParentColor default True;
    property ParentFont: Boolean read FParentFont write SetParentFont default True;
    property ParentShowHint: Boolean read FParentShowHint write SetParentShowHint default True;
    property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
    property ScalingFlags: TScalingFlags read FScalingFlags write FScalingFlags;
    property Text: TCaption read GetText write SetText;
    property WheelAccumulator: Integer read FWheelAccumulator write FWheelAccumulator;
    property WindowText: string read FText write FText;
    property Color: TColor read FColor write SetColor stored IsColorStored default clWindow;
    property Font: TFont read FFont write SetFont stored IsFontStored;
    property WindowText: PChar read FText write FText;
    property OnCanResize: TCanResizeEvent read FOnCanResize write FOnCanResize;
    property OnClick: TNotifyEvent read FOnClick write FOnClick stored IsOnClickStored;
    property OnConstrainedResize: TConstrainedResizeEvent read FOnConstrainedResize write FOnConstrainedResize;
    property OnContextPopup: TContextPopupEvent read FOnContextPopup write FOnContextPopup;
    property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
    property OnDragDrop: TDragDropEvent read FOnDragDrop write FOnDragDrop;
    property OnDragOver: TDragOverEvent read FOnDragOver write FOnDragOver;
    property OnEndDock: TEndDragEvent read FOnEndDock write FOnEndDock;
    property OnEndDrag: TEndDragEvent read FOnEndDrag write FOnEndDrag;
    property OnMouseActivate: TMouseActivateEvent read FOnMouseActivate write FOnMouseActivate;
    property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
    property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
    property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
    property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
    property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;
    property OnMouseWheel: TMouseWheelEvent read FOnMouseWheel write FOnMouseWheel;
    property OnMouseWheelDown: TMouseWheelUpDownEvent read FOnMouseWheelDown
      write FOnMouseWheelDown;
    property OnMouseWheelUp: TMouseWheelUpDownEvent read FOnMouseWheelUp write
      FOnMouseWheelUp;
    property OnResize: TNotifyEvent read FOnResize write FOnResize;
    property OnStartDock: TStartDockEvent read FOnStartDock write FOnStartDock;
    property OnStartDrag: TStartDragEvent read FOnStartDrag write FOnStartDrag;


et par la magie du transtypage on y a accès ... on peut donc aussi faire ceci:
  TLabel(Bevel1).PopupMenu := PopupMenu1;

et on se retrouve avec PopupMenu sur un Bevel !!! :D

les autres comme "Color" peuvent être affectés mais sans aucune incidence car inutilisé par le composant "TBevel"
mais les évènements sont déclenchés si ils sont assignés

TLabel(Bevel1).Color:=ClRed,
je n'ai aucun message d'erreur ni à la compilation ni à l'exécution et la form ne devient pas rouge.
par contre ça ça fonctionne :p
TLabel(Form1).Color := clRed;

    
@+ Cirec
Voilà qui est intéressanr à découvrir. J'avoue que j'éprouve toujours comme un petit malaise quand je dois tenir
compte de la hiérarchie des classes.

Finalement, ce n'est donc pas une honteuse combine que j'ai trouvée, ni même un expédient, ni même une ruse mais
bien une solution.

Je pense que je réussirai à exploiter cette découverte . J'imagine déjà des choses amusantes. Si j'ai bien compris,
pas question de rendre un bouton autosize mais je pourrai m'amuser à faire surgir des popupmenus de tous mes
composants

Eh bien, bravo à nous tous et merci encore.