IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Composants VCL Delphi Discussion :

Poser un composant sur un control et attachement a un autre


Sujet :

Composants VCL Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    48
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 48
    Par défaut Poser un composant sur un control et attachement a un autre
    Bonjour,
    J'ai fait le code ci dessous pour un Panel avec les coins arrondies.
    Il fonctionne, sauf que lorsque je le pose sur un control dans une fenetre, il prends toujours comme control parent la MainForm.
    Je ne peux donc le déposer sur une pagecontrol par exemple au sur un autre panel.
    En dynamique, lorsque j'affecte le parent, pas de probleme ??
    Avez-vous une idée ?
    Merci.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
      TPanelArrondie = class(TPanel)
      private
        FRoundRect : boolean;
        FArrondieValue,FContourWidth : integer;
        FContourColor : Tcolor;
        procedure SetRoundRect(Value : boolean);
        procedure SetArrondieValue(value : integer);
        procedure SetContourColor(Value : Tcolor);
        procedure SetContourWidth(value : integer);
      protected
        { Protected declarations }
        procedure Paint;override;
      public
        { Public declarations }
        constructor Create(AOwner: TComponent); override;
        destructor  Destroy;override;
      published
        property RoundRect  : boolean  read FRoundRect write SetRoundRect;
        property ArrondieValue  : integer  read FArrondieValue write SetArrondieValue;
        property ContourColor  : Tcolor  read FContourColor write SetContourColor;
        property ContourWidth  : integer  read FContourWidth write SetContourWidth;
      end;
     
    procedure Register;
     
    implementation
     
    procedure Register;
    begin
      RegisterComponents('Supplément', [TPanelArrondie]);
    end;
    //********************************************************
    constructor TPanelArrondie.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
      Parent := TWinControl(AOwner); 
      usedockmanager := true;
      BevelOuter := bvNone;
      RoundRect := true;
      ArrondieValue := 10;
      DoubleBuffered := true;
      color := clSkyBlue;
      ContourColor := clblue;
      ContourWidth :=1;
      //code
    end;
    //********************************************************
    destructor TPanelArrondie.Destroy;
    begin
    //code
      inherited Destroy;
    end;
    //********************************************************
    procedure TPanelArrondie.Paint;
    var
      Rect: TRect;
    begin
        	inherited Paint();
            Rect := GetClientRect;
            Canvas.Pen.Color := FContourColor;
            Canvas.Pen.Width := FContourWidth;
    	Canvas.Brush.Color := Parent.Brush.Color;
            Canvas.FillRect( Rect );
            Canvas.Brush.Color := Color;
            if ( FRoundRect ) then
            begin
              Canvas.RoundRect( Rect.Left, Rect.Top,
                                Rect.Right, Rect.Bottom , FArrondieValue, FArrondieValue );
     
            end
            else
                  Canvas.Rectangle( Rect.Left, Rect.Top,Rect.Right, Rect.Bottom);
     
    end;
    //********************************************************
    procedure TPanelArrondie.SetRoundRect(Value : boolean);
    begin
       FRoundRect := Value;
       paint;
    end;
    //********************************************************
    procedure TPanelArrondie.SetArrondieValue(value : integer);
    begin
     FArrondieValue :=value;
      paint;
    end;
    //********************************************************
    procedure TPanelArrondie.SetContourColor(Value : Tcolor);
    begin
     FContourColor := Value;
     paint;
    end;
    //********************************************************
    procedure TPanelArrondie.SetContourWidth(value : integer);
    begin
      FContourWidth := Value;
     paint;
    end;
    //********************************************************

  2. #2
    Membre émérite Avatar de slimjoe
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Canada

    Informations forums :
    Inscription : Juin 2005
    Messages : 647
    Par défaut
    Salut!

    Le problème est dans ton constructeur : tu mets AOwner comme parent. Le propriétaire du composant est celui qui va détruire ce dernier. Ce n'est pas son parent. Sur une fiche, tous les composants ont cette dernière comme propriétaire (en fait, quand tu places ton composant sur la fiche, c'est comme si tu faisais : TPanelArrondie.Create(self), self étant un pointeur sur la fiche en cours et non sur le composant sur lequel tu as déposé ton panel). Quand la fiche se détruit, elle détruit tous les composants qu'elle possède.

    Le parent est le composant qui contient visuellement un autre composant. Si tu détruis le parent, l'enfant reste toujours en mémoire jusqu'à ce que tu le détruises toi même ou que son propriétaire le fasse.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      Parent := TWinControl(AOwner);
    Est-ce que cette ligne est vraiment nécessaire ? Je crois que non... Enlève là pour voir .

    Bon dev!

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    48
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 48
    Par défaut
    Bonjour,

    Merci pour la reponse.
    J'ai essaye sans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Parent := TWinControl(AOwner);
    Mais j'ai l'erreur suivante :
    "Le controle n'a pas de fenetre parente".
    Donc voilà pourquoi j'ai ajouté cette ligne.
    Si vous avez d'autres idées ?
    Merci

  4. #4
    Membre émérite Avatar de slimjoe
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Canada

    Informations forums :
    Inscription : Juin 2005
    Messages : 647
    Par défaut
    Citation Envoyé par Annaced
    Bonjour,

    Merci pour la reponse.
    J'ai essaye sans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Parent := TWinControl(AOwner);
    Mais j'ai l'erreur suivante :
    "Le controle n'a pas de fenetre parente".
    Donc voilà pourquoi j'ai ajouté cette ligne.
    Si vous avez d'autres idées ?
    Merci
    Est-ce que tu as cette erreur lorsque tu place le composant sur ta fiche ou lorsque tu le créé en code ?

    Si tu créé ton composant dans le code, effectivement, il faut que tu spécifie le parent (comme n'importe quel composant d'ailleurs).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    with TPanelArrondie.Create(self) do
    begin
      Parent := MonParent;
      Visible := true;
    end;
    Mais si tu le déposes sur ta fiche en design time, je ne crois pas que ça soit nécessaire...

  5. #5
    Expert confirmé

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Par défaut
    Citation Envoyé par Annaced
    J'ai essaye sans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Parent := TWinControl(AOwner);
    Mais j'ai l'erreur suivante :
    "Le controle n'a pas de fenetre parente".
    Donc voilà pourquoi j'ai ajouté cette ligne.
    Il ne faut pas ajouter des lignes pour essayer de palier des erreurs commises ailleurs Ca mène toujours à des erreurs encore plus monstrueuses

    Il faudrait que tu nous dises quelle est la ligne de code qui déclenche cette erreur. Si cela n'apparaît qu'en conception, et que tu ne peux donc pas déboguer avec le débogueur, fais-le à coups de ShowMessage
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  6. #6
    DMO
    DMO est déconnecté
    Membre chevronné
    Avatar de DMO
    Profil pro
    Inscrit en
    Février 2004
    Messages
    290
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 290
    Par défaut
    Salut,

    À vue de nez comme ça, enlève les Paint dans les setters (procedure Set*), et ça devrait marcher (recompiles bien le paquet après !).

    Si vraiment il les faut, essaye avec un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      if NOT (csDesigning in ComponentState) then
        Invalidate;
    [Edit]De plus, bien entendu, je ne précise pas pour ne pas paraphraser srjd et slimjoe, mais je suis en parfaite harmonie avec eux au sujet de la ligne où tu assignes le Parent qui n'a rien à faire là. En conception le parent est assigné tout seul, et dynamiquement tu l'assignes par code.[/Edit]

    Bon dev'

  7. #7
    Expert confirmé

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Par défaut
    Citation Envoyé par DMO
    À vue de nez comme ça, enlève les Paint dans les setters (procedure Set*), et ça devrait marcher (recompiles bien le paquet après !).
    Euh ouais je me suis bêtement arrêté au Parent Mais c'est vrai que Paint devrait être remplacé par Invalidate. Il ne faut pas appeler Paint directement : c'est le traitement du message WM_PAINT qui appelle la méthode Paint.
    Citation Envoyé par DMO
    Si vraiment il les faut, essaye avec un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      if NOT (csDesigning in ComponentState) then
        Invalidate;
    Je sens que je vais me faire tapper mais euh... C'est pas vraiment une bonne idée non plus Certes ça va régler les problèmes, mais c'est un manque cruel à la logique de la conception des composants : ils sont en effet censés refléter la même apparence en conception qu'en exécution.

    L'utilisation de Invalidate en lieu et place de tes Paint fonctionnera et sera logique du point de vue conceptuel

    Bon je vais encore paraître vache mais je vais me permettre de commenter quelques passages de ton code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      published
        property RoundRect  : boolean  read FRoundRect write SetRoundRect;
        property ArrondieValue  : integer  read FArrondieValue write SetArrondieValue;
        property ContourColor  : Tcolor  read FContourColor write SetContourColor;
        property ContourWidth  : integer  read FContourWidth write SetContourWidth;
    Il faudrait ajouter des valeurs par défaut à ces propriétés, pour minimiser la taille du flux, ainsi que surcharger les valeurs par défaut des propriétés héritées que tu modifies dans le constructeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
      published
        property BevelOuter default bvNone;
        property Color default clSkyBlue;
        property UseDockManager default True;
        property RoundRect : boolean read FRoundRect write SetRoundRect default True;
        property ArrondieValue : integer read FArrondieValue write SetArrondieValue default 10;
        property ContourColor : Tcolor read FContourColor write SetContourColor default clBlue;
        property ContourWidth : integer read FContourWidth write SetContourWidth default 1;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure Register;
    begin
      RegisterComponents('Supplément', [TPanelArrondie]);
    end;
    Alors là je pousse à bout mais techniquement il aurait fallu mettre cette méthode dans un package à part, un package de conception. Et garder le code utile, celui du composant même, dans un package d'exécution.
    Mais ne t'en fais pas trop pour ça si tu ne cherches pas à faire parfait

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    usedockmanager := true;
    Je crois que tu ne devrais pas modifier cette propriété ici. En quoi l'utilisation ou non d'un dock-manager a-t-elle à voir avec les arrondis d'un panel ? J'ai l'impression que tu veux le faire pour t'éviter de le faire dans ton projet. Mais imagine que tu veuilles réutiliser ton composant dans un autre projet, tu seras vu D'autant plus vu que tu ne pourras même plus la remettre à False, étant donné que tu n'avais pas surchargé la valeur par défaut de la propriété.

    Je préconise donc vivement le retrait pur et simple de cette ligne de ton code (et donc ne pas ajouter la surcharge que j'ai donnée un peu plus haut ).

    Pour terminer, et pour faire les choses tout à fait proprement, tu aurais dû créer une classe TCustomPanelArrondie dérivant de TCustomPanel, dans laquelle les nouvelles propriétés, ainsi que les valeurs par défaut, sont déclarées protected ; puis en hériter un TPanelArrondie, en augmentant simplement la portée des propriétés par une redéclaration en section published.


    Bon cela dit j'ai vraiment été au fond des choses, et il se peut que tu l'aie mal pris. J'espère que non, car ce n'est pas le but : j'essaye de te donner un maximum de conseil pour développer ton composant de façon la plus propre possible.
    Et qui dit plus propre, dit aussi plus sûr ; et cela est particulièrement vrai dans le domaine de la conception des composants.
    Voici aussi un gros tutoriel (dont la moitié des parties sont rédigées seulement, mais c'est suffisant pour un très bon départ) sur la création de composants.
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  8. #8
    DMO
    DMO est déconnecté
    Membre chevronné
    Avatar de DMO
    Profil pro
    Inscrit en
    Février 2004
    Messages
    290
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 290
    Par défaut
    Salut Srjd,

    Citation Envoyé par srjd
    Je sens que je vais me faire tapper mais euh...
    Mais non : premièrement, j'ai, pour l'instant, toujours apprécié ton approche objet (pour pas dire simplement "propre") à la lecture des messages de ta plume (du moins ceux qui me sont passés sous les yeux), et deuxièmement, personne n'est à l'abri de dire une c#######nerie, comme ça en passant, à l'occasion...
    Citation Envoyé par srjd
    ils sont en effet censés refléter la même apparence en conception qu'en exécution.
    Nous sommes bien d'accord. Pour "expliquer" cette suggestion à moitié malheureuse, voici : j'ai cru comprendre que le Paint qu'il avait mis dans ses setters ne lui posait problème qu'en conception, d'où la très mauvaise idée du "if". Ensuite je me suis dit "mais m#### !, pourquoi fait-il un Paint ? c'est plutot un Invalidate qu'il faut !". Puis j'ai bêtement oublié d'enlever la condition...

    Tu fais donc bien de me reprendre. Oui un simple Invalidate inconditionnel c'est ce qu'il faut.

    De plus (bon je te rassure de suite : je suis pas tombé amoureux hein... ) c'est bien que tu ais creusé : j'approuve tes remarques, et j'ajouterais simplement, mais c'est un choix qui n'appartient qu'au développeur de ce composant visuel, que pour ma part j'aurais laissé la couleur à clBtnFace et mis par défaut celle du contour à clBtnHighlight ou clBtnShadow. Ensuite à l'utilisateur de faire correspondre ces propriétés à une éventuelle interface graphique aux couleurs "en dur".

    Bon dev'

Discussions similaires

  1. Réponses: 12
    Dernier message: 12/12/2004, 15h25
  2. Réponses: 3
    Dernier message: 11/05/2004, 19h39
  3. [VB6]Existence d'un image sur un control
    Par oazar dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 27/04/2004, 18h00
  4. [VB.Net] Faire du JS sur des contrôles côté serveur
    Par TagadaTsoin dans le forum ASP.NET
    Réponses: 4
    Dernier message: 03/11/2003, 16h51
  5. [VB6] Comment boucler sur des controls d'un form ?
    Par lankviller dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 27/01/2003, 17h29

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo