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 :

Styles et les contrôles créés dynamiquement


Sujet :

Composants VCL Delphi

  1. #1
    Invité
    Invité(e)
    Par défaut Styles et les contrôles créés dynamiquement
    Bonjour,

    Dans une application des contrôles sont créés dynamiquement et doivent restés flottants pour (non recensés : parent = nil) pour éviter de perturber l'arbre d'alignement des contrôles du parents, mais si un style est sélectionné ces contrôles provoquent des violations d’accès et autres problèmes selon le contrôle du fait qu'ils appellent le parent qui est à nil

    Ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
       with TButton.Create(Self)do
       begin
           Top := 20;
           Left := 300;
           Caption := 'test';
           ParentWindow := Self.Handle;
       end;
    Si on clique sur ce bouton il aura une violation d’accès

  2. #2
    Membre expérimenté
    Avatar de XeGregory
    Homme Profil pro
    Passionné par la programmation
    Inscrit en
    Janvier 2017
    Messages
    672
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Passionné par la programmation
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Janvier 2017
    Messages : 672
    Billets dans le blog
    1
    Par défaut
    Ce qui se passe : tu crées un TButton avec Parent := nil et tu relies uniquement son ParentWindow au handle du formulaire.
    Cela fonctionne tant que tu ne touches pas au bouton, mais dès qu’il reçoit un message (clic, focus, etc.), la VCL tente d’accéder à son Parent (qui est nil) : violation d’accès.

    Les contrôles VCL (comme TButton) sont des TWinControl descendants.
    Ils ont besoin d’un Parent (un autre TWinControl) pour gérer leur fenêtre et leur style.
    Si tu mets Parent := nil, mais que tu assignes ParentWindow := Self.Handle, tu crées une incohérence : le contrôle croit avoir une fenêtre parente, mais pas d’objet parent VCL.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    with TButton.Create(Self) do
    begin
      Parent := Self;   // rattache au formulaire
      Top := 20;
      Left := 300;
      Caption := 'test';
    end;

  3. #3
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 177
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 177
    Par défaut
    Même dans des DLL C++, j'ai fais une entorse à la règle de passer uniquement des types simples ou compatible OLE uniquement pour ce cas, un SetParent via un TWinControl posait beaucoup moins de problème que le ParentWindow (perte de Focus, évènement non déclenché ...), j'ai pu le faire évidemment puisque EXE et DLL compilé avec BPL

    Je ne vois pas à quel moment dans un EXE, on aurait besoin d'avoir un Parent à nil, mon expérience c'est que cela pose beaucoup trop de problème dans la logique VCL
    En plus Owner à Self et Parent à nil, la VCL ne doit pas aimer ce mélange, c'est tout ou rien,
    soit VCL 100% donc Owner et Parent définis,
    soit externe 100% (OLE par exemple), donc Onwer et Parent à nil + CreateParented

    Si tu as un problème d'alignement au niveau des Parent, je pense que tu devrais revoir tes Align et Anchors, tu peux créer un control "volant", voir cas extrême d'un DisableAlign()
    Il te manque peut-être des TPanel intermédiaires servant de Parent pour les Boutons et de Parent pour les contrôles alignés sans qu'ils se pertubent.



    Si tu veux créer un bouton totalement hors VCL, faut le faire à la main via CreateWindow BS_DEFPUSHBUTTON

    Tu peux aussi le dessiner via un DrawFrameControl


    J'ai utilisé CreateParented et ParentWindow pour "exposer" un controle, par exemple un TTreeView dans une DLL/OLE qui est utilisé par un EXE non VCL (Exemple Plugin Navision) donc pas de thème, pas de mécanisme de VCL qui se propage ... faut bien penser à quoi sert ParentWindow
    CreateParented, le Owner est implicitement nil puisqu'il est prévu que l'on gère sa création et libération par un tiers.
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  4. #4
    Invité
    Invité(e)
    Par défaut
    Le but est pour ajouter des boutons à une listbox standard pour les opérations ajouter/supprimer et autres ce qui évite de les créer manuellement à chaque fois, après l'insertion de l'unité dans les uses on peut sélectionner les listbox sur lesquelles ce paneau doit être affiché..



    l'affectation du Parent fonctionne mais par précaution et pour la perinité du code je ne veux pas parasiter le parent de la listbox par ces contrôles qui peuvent perturber son fonctionnement.

    le panel est le seul contrôle qui ne déclenche pas une exception les TLabels, TSpeedButtons c'est encore pire ils provoquent l'erreur juste après la création avant mème qu'on clique dessus.

    la limite inférieure du Client de la listbox est réduite par WM_NCCALCSIZE pour permettre l'installation du panel en bas ça marche bien j'ai voulu aussi une bande latérale pour y placer des checkboxs mais sur une listbox avec style le scrollbar vertical ne s'affiche pas exactement à droite mais déplacé à gauche l'opposé de la marge ajouté.

  5. #5
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 177
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 177
    Par défaut
    Comment vas-tu gérer la superpositon du dernier item ?

    Un panel parent de la listbow, un panel bottom pour les boutons c'est réglé
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Membre chevronné Avatar de der§en
    Homme Profil pro
    Chambord
    Inscrit en
    Septembre 2005
    Messages
    1 243
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : Chambord
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 243
    Par défaut
    Peut-être en modifiant TListbox.ClientHeight et ClientWidth, voir TListbox.ClientRect

  7. #7
    Invité
    Invité(e)
    Par défaut
    Comment vas-tu gérer la superpositon du dernier item ?
    Le dernier élément n'est pas marqué et on peut l'atteindre car la hauteur du client a été réduite et le panel couvre la zone non client, comme cité avant, le message WM_NCCALCSIZE émis juste après la création de la fenêtre du contrôle permet de déterminer la position et les dimensions du client.



    On peut dessiner dans cette zone NC par l'interception de WM_NCPANT mais attention avec un style ce message n'est plus envoyé on doit retirer csBorder du StyleElements pour pouvoir dessiner.

    j'ai voulu aussi une bande latérale pour y placer des checkboxs mais sur une listbox avec style le scrollbar vertical ne s'affiche pas exactement à droite mais déplacé à gauche l'opposé de la marge ajouté.
    Voila à quoi ressemble.. il parait que les styles Delphi ne tient pas compte des modifications apportées par WM_NCPANT et considère que le client est toujours à la position 0.. on peut voir le mirage du scrollar décalé vers la gauche si on clique dessus y a rien on sélectionne un élément de la liste par contre la vrai scrollbox reste à sa place si on clique là ou il devrait être on voit que la liste bouge.


  8. #8
    Membre Expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 573
    Par défaut
    Bonjour,
    pour les cases à cocher il y a le control CheckListBox ?

    A+
    Charly

  9. #9
    Membre expérimenté
    Avatar de XeGregory
    Homme Profil pro
    Passionné par la programmation
    Inscrit en
    Janvier 2017
    Messages
    672
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Passionné par la programmation
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Janvier 2017
    Messages : 672
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Charly910 Voir le message
    Bonjour,
    pour les cases à cocher il y a le control CheckListBox ?

    A+
    Charly
    Pourquoi faire compliqué quand on peut faire simple ?

    Citation Envoyé par Mist2024 Voir le message
    Le dernier élément n'est pas marqué et on peut l'atteindre car la hauteur du client a été réduite et le panel couvre la zone non client, comme cité avant, le message WM_NCCALCSIZE émis juste après la création de la fenêtre du contrôle permet de déterminer la position et les dimensions du client.



    On peut dessiner dans cette zone NC par l'interception de WM_NCPANT mais attention avec un style ce message n'est plus envoyé on doit retirer csBorder du StyleElements pour pouvoir dessiner.



    Voila à quoi ressemble.. il parait que les styles Delphi ne tient pas compte des modifications apportées par WM_NCPANT et considère que le client est toujours à la position 0.. on peut voir le mirage du scrollar décalé vers la gauche si on clique dessus y a rien on sélectionne un élément de la liste par contre la vrai scrollbox reste à sa place si on clique là ou il devrait être on voit que la liste bouge.

    Sans code, cela va être difficile de trouver ton problème.
    On ne peut pas faire confiance à un code qu'on n'a pas entièrement écrit soi‑même, et encore moins à celui qu'on a écrit entièrement. :aie:

  10. #10
    Invité
    Invité(e)
    Par défaut
    pour les cases à cocher il y a le control CheckListBox ?
    Oui je savais et j'ai bien pioché dans le code de cette liste pour voir comment les checkboxs sont ajoutés mon but c'est améliorer la listbox

    Sans code, cela va être difficile de trouver ton problème.
    La solution est dans la désactivation des styles pour la bordure.


    Pour reproduire ce dernier bug placer une listbox dans une form et ajouter ce code:
    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
      TListBox = class(Vcl.StdCtrls.TListBox)
      private
       procedure WMNCCalcSize(var Msg: TWMNCCalcSize); message WM_NCCALCSIZE;
      end;
     
      TForm1 = class(TForm)
        ListBox1: TListBox;
        procedure FormCreate(Sender: TObject);
      private
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
     
    procedure TListBox.WMNCCalcSize(var Msg: TWMNCCalcSize);
    begin
      inherited;
       with Msg.CalcSize_Params.rgrc[0]do
         Left := Left + 25;
    end;
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
    i: integer;
    begin
     for I := 0 to 40 do
        listbox1.Items.Add('Item ' +  i.ToString)
    end;

  11. #11
    Membre expérimenté
    Avatar de XeGregory
    Homme Profil pro
    Passionné par la programmation
    Inscrit en
    Janvier 2017
    Messages
    672
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Passionné par la programmation
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Janvier 2017
    Messages : 672
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Mist2024 Voir le message
    Oui je savais et j'ai bien pioché dans le code de cette liste pour voir comment les checkboxs sont ajoutés mon but c'est améliorer la listbox



    La solution est dans la désactivation des styles pour la bordure.


    Pour reproduire ce dernier bug placer une listbox dans une form et ajouter ce code:
    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
      TListBox = class(Vcl.StdCtrls.TListBox)
      private
       procedure WMNCCalcSize(var Msg: TWMNCCalcSize); message WM_NCCALCSIZE;
      end;
     
      TForm1 = class(TForm)
        ListBox1: TListBox;
        procedure FormCreate(Sender: TObject);
      private
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
     
    procedure TListBox.WMNCCalcSize(var Msg: TWMNCCalcSize);
    begin
      inherited;
       with Msg.CalcSize_Params.rgrc[0]do
         Left := Left + 25;
    end;
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
    i: integer;
    begin
     for I := 0 to 40 do
        listbox1.Items.Add('Item ' +  i.ToString)
    end;
    Ton code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    with Msg.CalcSize_Params.rgrc[0] do
      Left := Left + 25;
    Tu réduit la zone client de 25 pixels à gauche.
    Mais le ListBox n’est pas conçu pour gérer une zone client réduite de cette manière.
    Le moteur interne de TWinControl suppose que le client rect correspond exactement à la zone disponible pour les items.

    Dessiner manuellement les items avec Style := lbOwnerDrawFixed et gérer le décalage dans OnDrawItem

    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
    type
      TForm1 = class(TForm)
        ListBox1: TListBox;
        procedure FormCreate(Sender: TObject);
        procedure ListBox1DrawItem(Control: TWinControl; Index: Integer;
          Rect: TRect; State: TOwnerDrawState);
      private
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
      i: Integer;
    begin
      // Active le mode OwnerDraw
      ListBox1.Style := lbOwnerDrawFixed;
      ListBox1.ItemHeight := 18; // hauteur des items
     
      for i := 0 to 40 do
        ListBox1.Items.Add('Item ' + i.ToString);
    end;
     
    procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
    begin
      with (Control as TListBox).Canvas do
      begin
        FillRect(Rect);
        // décalage manuel de 25 px
        TextOut(Rect.Left + 25, Rect.Top, (Control as TListBox).Items[Index]);
      end;
    end;
    Style := lbOwnerDrawFixed : tu prends la main sur le rendu des items.
    ItemHeight : fixe la hauteur de chaque ligne.
    Dans OnDrawItem, tu déplaces le texte de 25 pixels (Rect.Left + 25).

    Tu gardes un rendu stable, sans bug lié à la zone client ou aux scrollbars.
    Résultat : même effet visuel (texte décalé à droite), mais robuste et propre, sans interférer avec les messages Windows.
    On ne peut pas faire confiance à un code qu'on n'a pas entièrement écrit soi‑même, et encore moins à celui qu'on a écrit entièrement. :aie:

  12. #12
    Invité
    Invité(e)
    Par défaut
    Mais le ListBox n’est pas conçu pour gérer une zone client réduite de cette manière.
    Le moteur interne de TWinControl suppose que le client rect correspond exactement à la zone disponible pour les items.
    Ce problème est uniquement avec les styles s'ils ne sont pas utilisés le code fonctionne comme prévu

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 05/05/2006, 17h44
  2. [CSS] Integrer Les Styles Et Les Forme Du Texte
    Par nizou1984 dans le forum Mise en page CSS
    Réponses: 1
    Dernier message: 14/03/2006, 03h13
  3. Plusieurs styles pour les liens
    Par oranoutan dans le forum Balisage (X)HTML et validation W3C
    Réponses: 4
    Dernier message: 11/01/2006, 12h49
  4. [VB.Net] Calendar et style sur les jours
    Par Sardonnen dans le forum ASP.NET
    Réponses: 1
    Dernier message: 18/11/2005, 11h23

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