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

Lazarus Pascal Discussion :

[0.9.31] Override dans un composant TStringGrid. Questions diverses


Sujet :

Lazarus Pascal

  1. #1
    Invité
    Invité(e)
    Par défaut [0.9.31] Override dans un composant TStringGrid. Questions diverses
    Bonjour,

    J'ai terminé l'étape de modification de mon composant TstringGrid et quelques questions restent sans réponse à mon niveau. En vrac,

    j'ai dans un premier temps voulu overrider OnSelection. Impossible, ai-je lu. Certes, mais pourquoi ? [Question 1]

    D'un autre côté, un code comme ceci semble fonctionner sous Windows. Ce n'est pas un override "classique" mais il semble rendre le même service. Est-ce le cas et ce code est-il acceptable ? [Question 2]
    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
    unit myStringGrid;
     
    {$mode objfpc}{$H+}
     
    interface
     
    uses
      [...]
     
     
    type
      TmyStringGrid = class(TStringGrid)
      private
        { Private declarations }
        { --Modification de l'évènement................................... [partie 1a]}
        FOnSelection        : TNotifyEvent;
     
     
    	{ --Modification de l'évènement................................... [partie 1b]}
        procedure SelfOnSelection(Sender : TObject; aCol, aRow: Integer);
      protected
        { Protected declarations }
     
      public
        { Public declarations }
     
      published
        { --Modification de l'évènement................................... [partie 1c]}
        property OnSelection : TNotifyEvent read FOnSelection write FOnSelection;
        { Published declarations }
     
     end;
     
    procedure Register;
     
    implementation
     
    procedure Register;
    begin
      [...]
    end;
     
    constructor TmyStringGrid.Create(AOwner: TComponent);
    var
     iLoc : integer;
     
    begin
      Inherited Create(AOwner);
      { --Modification de l'évènement................................... [partie 2]}
      FOnSelection := nil;
      Inherited OnSelection   := @SelfOnSelection;  
    end;	
     
      { --Modification de l'évènement................................... [partie 3] }
    procedure TmyStringGrid.SelfOnSelection(Sender: TObject; aCol, aRow: Integer);
    begin
      [...] {Mon code}
     
      if Assigned(FOnSelection) then FOnSelection(Sender); //ou Self ?
      {Cette dernière ligne est à éliminer s'il s'agit d'un code de remplacement et
       non d'un code complémentaire précédant ou suivant le code de l'utilisateur.
       Suivant le cas on peut la placer avant Mon code ou après}
    end;
     
    end.
    Mais pas sous Linux... Pour s'en convaincre, il suffit dans l'Inspecteur d'Objet du nouveau composant de créer un OnSelection.
    En Win on obtient : procedure TForm1.myStringGrid1Selection(Sender: TObject; aCol, aRow: Integer);
    Alors que sous Linux : procedure TForm1.myStringGrid1Selection(Sender: TObject); Pourquoi cette différence de comportement ? [Question 3]

    Bref, j'aimerais me mettre au clair avec ceci.

    D'un autre côté, j'ai overridé à la place SelectCell, comme me l'avait suggéré mick605. J'ai voulu un peu optimiser le code en limitant les invalidates
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function TmyStringGrid.SelectCell(ACol: Integer;ARow: Integer) : Boolean;
    begin
      {$IFDEF Linux}
      if FixedCols + 1 < RowCount - 1 then
       if (aCol = FixedCols + 1) and (aRow >= FixedRows) then
      {$ENDIF}
      {$IFDEF MsWindows}
      if (aCol = FixedCols) and (aRow >= FixedRows) then
      {$ENDIF}
      invalidate;
      inherited;
    end;
    Suivant le nombre de FixedCols, je ne comprends pas bien pourquoi, il y a une différence entre l'approche Windows et l'approche Linux. Cela ne fait pas l'objet de question.

    Enfin, je rencontre toujours ce problème agaçant : Que faut-il faire pour que toutes les modifications soient prises en compte notamment au niveau des properties ? Un clean and rebuild de Lazarus me semble parfois insuffisant... au point que je préfère parfois désinstaller le composant puis le réinstaller dans l'IDE. Dans les 2 cas, quelle perte de temps. Là, non plus. C'est une constatation et comme j'ai déjà plusieurs fois posé la question...

    Une dernière question, pour la prochaine étape : dans ma StringGrid multiselect, j'ai voulu utiliser des lignes de couleurs... Alors, le problème c'est qu'overrider DrawCell me semble "délicat". La colorisation ne pose pas de problème particulier... sauf si "en production", on utilise des images dans le OnDrawcell (de l'Insp. d'Objet du composant). Si on intègre le code de modification des couleurs dans DrawCell overridé du composant, je peux différencier le contexte (utilisation de Columns ou pas) mais comment peut-on différencier la présence d'une image de celle d'un texte à posteriori ?
    Dans le composant, grosso-modo :
    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
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); {override;}
    var
     [...]
    begin
      inherited;
     
      if (aCol >= FixedCols) and (aRow >= FixedRows)  then  begin
       sTmp := Cells[aCol,Arow];
     {On suppose ici  DEJA que c'est du texte... mais si la Cell contient déjà une
       image  (chargée par le inherited, c'est un post-traitement) comment la 
       détecte-t-on ?}
     
       {Gestion des couleurs de fond} [...]
       { Dessin du fond }
         FillRect(aRect);
       { Les polices } [...] 
       { Dessin du texte } [...]
        if Columns.Count > 0 then begin
         if Columns[aCol-1].Alignment = taLeftJustify then
          DrawText(Canvas.Handle, PChar(sTmp), length(sTmp), aRect,
                DT_SINGLELINE or DT_VCENTER or DT_LEFT or DT_END_ELLIPSIS)[...]
        end else
         {Pas de Tcolumn utilisé donc alignement à gauche}
         Canvas.TextRect(aRect, aRect.Left+3, aRect.Top-2, sTmp);
    end;
    Je n'ai malheureusement plus de temps à consacrer à ces problèmes mais les éventuelles réponses m'intéressent... pour les prochaines vacances scolaires.

    D'avance merci.
    Cordialement. Gilles
    Dernière modification par Invité ; 02/11/2011 à 20h00.

  2. #2
    Membre chevronné

    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Aveyron (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2009
    Messages : 935
    Points : 1 765
    Points
    1 765
    Par défaut
    Salut

    j'ai dans un premier temps voulu overrider OnSelection. Impossible, ai-je lu. Certes, mais pourquoi ? [Question 1]
    Tu ne peux pas overrider un evenement, car, par définition, c'est un pointeur sur une méthode, et non pas une méthode. Seules les methodes sont "overridealbles".

    D'un autre côté, un code comme ceci semble fonctionner sous Windows. Ce n'est pas un override "classique" mais il semble rendre le même service. Est-ce le cas et ce code est-il acceptable ? [Question 2]
    Je ne pense pas que cela soit tres propre, mais si c'est ta seule solution ...

    Pourquoi cette différence de comportement ? [Question 3]
    Franchement, je ne sais pas. Ce code compile-t-il ? Est ce que si tu corrige le code, comme sous windows, ca compile ?

    J'ai voulu un peu optimiser le code en limitant les invalidates
    Pour info, les invalidates ne repeignent pas le composant, il envoie juste un message au composant pour lui dire de se repeindre. Ainsi, si le composant est occupé, le message reste en attente jusqu'a que le composant n'ait plus rien a faire. Autrement dit, tu peux mettre plein d'invalidates a la suite, ca ne ralentira pas ta procedure. Reste a savoir si le composant sera repeint plusieurs fois ou non (j'espere que non).
    Une autre info, dans l'aide, je suis tombé par hasard sur InvalidateCell, InvalidateRow, etc. Dans ton cas, si je me souviens bien, pas la peine de tout repeindre, donc utilise un de ceux la.

    Alors, le problème c'est qu'overrider DrawCell me semble "délicat".
    C'est vrai. Un truc que tu peux faire, c'est appeler inherited apres ton traitement : si ce traitement affiche une image, alors elle s'affichera par dessus ton texte déja affiché. C'est quand même contre performant.

    Un autre moyen, c'est de créer un type pour l'évenement OnDrawCell, qui prend un parametre de plus nommé DefaultPaint, de type boolean, du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    procedure TForm1.StringGrid2DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState; var DefaultPaint : boolean);
    Suivant l'état de cette variable, tu dessine ou pas.

    3eme technique, tu crée 2 évenements, OnBeforePaintCell et OnAfterPaintCell, et tu en lance un avant le dessin, un apres. L'utilisateur devra choisir ou placer son code suivant le résultat voulu.

    En esperant avoir été utile, bonne chance

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour Mick605,

    A propos du pseudo override d'OnDrawCell
    Citation Envoyé par mick605 Voir le message
    Je ne pense pas que cela soit tres propre, mais si c'est ta seule solution ...
    Non, je ne l'utilise pas. Ce n'est pas la seule méthode. Je travaille ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    procedure PrepareCanvas(aCol,aRow: Integer; aState: TGridDrawState); override;
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
    Le pseudo-override (OnSelfDrawCell) compile aussi bien en Win qu'en Nux... mais son utilisation est impossible si on veut utiliser le "vrai" OnDrawcell du composant sous Linux. Il semble fonctionner sous Windows... mais je n'ai pas fait tous les tests nécessaires. J'ai trouvé un (seul) code approchant sur un forum. Ce qui m'a étonné, c'est la différence de "fonctionnement" dans les 2 OS.

    Citation Envoyé par mick605 Voir le message
    Pour info, les invalidates ne repeignent pas le composant, [...] Reste a savoir si le composant sera repeint plusieurs fois ou non (j'espere que non).
    Une autre info, dans l'aide, je suis tombé par hasard sur InvalidateCell, InvalidateRow, etc. Dans ton cas, si je me souviens bien, pas la peine de tout repeindre, donc utilise un de ceux la.
    Repeindre plusieurs fois ? Le TStringGrid.OnDrawCell n'arrête pas ! C'est pour cela que je voulais limiter les invalidates.
    Pour le invalidateCell, je n'obtiens aucun résultat. Cela ne semble pas fonctionner. Il y a une subtilité que je ne maîtrise pas entre invalidatexxx et l'évènement à l'origine de son déclenchement. Ainsi, pour le invalidateRow cela fonctionne partiellement sur le composant avec l'usage de MouseWheel à condition que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function TmyStringGrid.SelectCell(ACol: Integer;ARow: Integer) : Boolean;
    begin
      if aRow+1 <= RowCount -1 then InvalidateRow(aRow+1);  {MouseWheelDown}
      InvalidateRow(aRow-1);                              {MouseWheelUp}
      inherited;
    end;
    ... Dans ce cas, lorsqu'on utilise la roulette de la souris, la colonne 0 (celle qui contient les Bitmap de focus ou de sélection) est bien remise à jour. Mais avec ce code, pour le click, cela dépend de la position du pointeur de la souris. L'ancienne position de Focus par exemple n'est pas nécessairement effacée. Donc finalement j'ai adopté le plus simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function TmyStringGrid.SelectCell(ACol: Integer;ARow: Integer) : Boolean;
    begin
      invalidate;
      inherited;
    end;
    Citation Envoyé par mick605 Voir le message
    En esperant avoir été utile, bonne chance
    Oui très utile comme d'habitude... Pour le reste des infos, je stocke. Merci.
    Bonne journée.
    Cordialement. Gilles
    Dernière modification par Invité ; 03/11/2011 à 12h10.

  4. #4
    Membre chevronné

    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Aveyron (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2009
    Messages : 935
    Points : 1 765
    Points
    1 765
    Par défaut
    Citation Envoyé par selzig Voir le message
    Repeindre plusieurs fois ? Le TStringGrid.OnDrawCell n'arrête pas ! C'est pour cela que je voulais limiter les invalidates.
    Pour le invalidateCell, je n'obtiens aucun résultat. Cela ne semble pas fonctionner. Il y a une subtilité que je ne maîtrise pas entre invalidatexxx et l'évènement à l'origine de son déclenchement. Ainsi, pour le invalidateRow cela fonctionne partiellement sur le composant avec l'usage de MouseWheel à condition que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function TmyStringGrid.SelectCell(ACol: Integer;ARow: Integer) : Boolean;
    begin
      if aRow+1 <= RowCount -1 then InvalidateRow(aRow+1);  {MouseWheelDown}
      InvalidateRow(aRow-1);                              {MouseWheelUp}
      inherited;
    end;
    C'est pas exactement ce que je voulais dire :
    Citation Envoyé par Aide Delphi XE2 - Invalidate
    Redessine entièrement le contrôle.

    Utilisez Invalidate quand la totalité du contrôle doit être dessinée. Si plusieurs zones d'un contrôle doivent être redessinées, Invalidate provoque le réaffichage de toute la fenêtre en une seule passe, pour éviter les instabilités provoquées par les redessins redondants. Les performances ne sont pas dégradées par plusieurs appels d'Invalidate avant que le contrôle ne soit effectivement redessiné.
    http://docwiki.embarcadero.com/VCL/X...rol.Invalidate

    Mais ce n'est pas le plus important. A propos de InvalidateXXX, je ne m'en suis jamais servi. Ton probleme, en fait, est que si tu ne fait pas ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function TmyStringGrid.SelectCell(ACol: Integer;ARow: Integer) : Boolean;
    begin
      invalidate;
      inherited;
    end;
    ... tu as le dessin des FixedCols qui n'est pas appelé, je me trompe ?

    Pour cela, tu peux éviter un rafraichissement de toute ta grille en faisant un simple InvalidateCol(0);

    Bonne chance !

  5. #5
    Invité
    Invité(e)
    Par défaut
    Bonjour Mick605,

    Ce code passe effectivement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    invalidateCol(0); // à la place de invalidate;
    inherited;
    Merci pour les réf. documentaires. Bonne journée.
    Gilles

Discussions similaires

  1. Problème d'affichage dans un composant TScrollBox
    Par erossi dans le forum Composants VCL
    Réponses: 3
    Dernier message: 14/09/2005, 11h29
  2. Réponses: 4
    Dernier message: 27/07/2005, 11h51
  3. Les champs dans un composant ADOStorecProc
    Par ZIED dans le forum Bases de données
    Réponses: 3
    Dernier message: 22/06/2005, 11h32
  4. Ecrire du texte en couleurs dans un composant
    Par wutang dans le forum Composants
    Réponses: 11
    Dernier message: 12/07/2004, 10h55
  5. Une image dans un composant ?
    Par bjl dans le forum Composants VCL
    Réponses: 2
    Dernier message: 20/03/2003, 11h28

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