Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

MODIFIEZ DES COMPOSANTS EXISTANTS SANS MODIFIER VOS FICHES EXISTANTES (+ DIDACTICIEL)


Information sur la source

Catégorie :Composants Niveau : Débutant Date de création : 15/01/2005 Date de mise à jour : 15/01/2005 16:06:59 Vu / téléchargé: 3 996 / 695

Note :
9,8 / 10 - par 5 personnes
9,80 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (19)
Ajouter un commentaire et/ou une note

Description

Une fois n'est pas coutume : le code que je dépose aujourd'hui ne comporte aucun commentaire. En revanche, vous trouverez toutes les explications dans le document joint (pdf).
Pourquoi ?
Pour deux raisons :
1- les didacticiels ne sont pas assez mis en évidence sur le site, ce qui décourage beaucoup d'entre nous d'en faire (faut bien trouver une excuse :o))
2- un didacticiel sans code source adossé, ça ne reste, trop souvent, que de la théorie pure. Aussi, je me suis dit qu'en joignant les deux dans l'archive, je ferai d'une pierre deux coups (et non pas...)

Trêve de bavardage, ce code (surtout le didacticiel) a pour objectif de vous montrer une démarche :
1- à mi-chemin entre la création d'un nouveau composant et son cortège d'inconvénients
2- plus lègère que celle consistant à déclarer une classe à usage presque unique

Vous trouverez la comparaison des différentes méthodes dans le didacticiel ainsi que leurs points forts et leurs points faibles.

Le code source est suffisamment simple pour être à la portée des débutants.

J'ose espérer, comme il est dit dans la conclusion du didacticiel, que cela mettra fin aux différentes discussions quand un membre publie un code source nécessitant l'utilisation de composants spécifiques qu'on a pas forcément l'envie d'installer dans son environnement de travail.


 

Conclusion

Réalisé avec Delphi 7.
Aucune installation de composants additionnels n'est nécessaire. :o]

Seules les remarques constructives sont acceptées.
 

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Historique

15 janvier 2005 15:35:25 :
Juste un petit souci avec le nom du fichier pdf sur ce site.
15 janvier 2005 15:35:33 :
Juste un petit souci avec le nom du fichier pdf sur ce site.
15 janvier 2005 16:07:01 :
Pages doublées dasn le pdf décidément !). Merci à JulioDelphi de m'avoir signalé ce problème.

Commentaires et avis

signaler à un administrateur
Commentaire de JulioDelphi le 15/01/2005 18:28:04 administrateur CS

:)
Magnifique ! les expliquations sont trèès détaillées et très bonnes ! J'ai appris des choses "de base" grâce a cette lecture (10 minutes suffisent).
Ca me donne envie de faire de meme avec la création complete de composants :)
Bravo encore DelphiProg !
10/10

ps : ça reponds encore mieux a la question du forum

signaler à un administrateur
Commentaire de ManChesTer le 15/01/2005 20:58:00 administrateur CS

Petite question stupide...

As-tu étudié le code généré par le compilateur et ses performances ?

Amicalement

ManChesTer.

signaler à un administrateur
Commentaire de Inekman le 16/01/2005 13:51:44

excellente cette astuce. Chapeau bas Delphiprog.

signaler à un administrateur
Commentaire de Delphiprog le 16/01/2005 23:52:58 administrateur CS

Merci InekMan.

Manchester : venant de toi, je suis sur que tu as une arrière pensée et que ta question ne peut pas être stupide. Je la prend donc très au sérieux.

Le code généré par le compilateur dénote une différence d'1 Ko environ par rapport à l'utilisation d'un TStaticText standard. Mais cette différence est faussée dans la mesure où, pour la réaliser, on doit désactiver une partie du code de l'unité de la fiche.
Il serait mieux de comparer avec un nouveau composant qui soit réellement un descendant de TStaticText.
Il faudrait aussi mesurer le temps passé à construire un paquet, à l'installer puis, et c'est surement là que le bât blesse, à remplacer tous les TStatictext par le nouveau composant créé. Les utilisateurs des outils GExperts apprécieront l'efficacité de la commande "Replace components". Mais il faudra, malgré tout, inspecter fiche après fiche et procéder aux remplacements nécessaires.
C'est donc un travail fastidieux à réaliser pour des applications comportant des dizaines de fiches.

Bien entendu, cette technique n'entend pas se substituer à celle de la "vraie" création de composants réutilisables pour de futures applications. Elle vise simplement à remplacer très rapidement un type de composant sans devoir remanier les boites de dialogue d'une application.
Et là, je dirai qu'il n'y a pas photo en temps de mise en oeuvre.

Les performances du code ?
Je serais tenté de rapprocher ma démarche à celle d'un transtypage de classe. Et là, on ne se pose jamais la question. Et pourtant...
On ne se la pose pas beaucoup plus quand il faut utiliser des directives comme Dynamic ou Virtual...et là dessus, les créateurs de composants feraient bien de se demander quelle option est la meilleure pour la suite. Encore faudrait-il qu'ils connaissent la nuance...

Quant à utiliser des intruments de mesure, il faudrait le faire sur une application plus importante que celle ci pour obtenir des mesures significatives.

Je reste ouvert à toutes propositions.

Encore merci Manchester d'avoir ouvert un débat qui promet d'être passionnant.

signaler à un administrateur
Commentaire de MAURICIO le 17/01/2005 14:52:03

En tout cas, c très bien expliqué!
Même moi, qui ne fais pas de compos, g presque tout pigé. J' ai qques trucs que je ne comprends pas:
- Ne serait-il pas plus simple de chercher les dfm qui utilisent le compo pour remplacer la déclaration de la class par une autre? TStaticText vers TStaticTextEx?
Ça a l' avantage de pouvoir utiliser les 2 class et le systeme ajoutera les propriétés/events automatiquement (enfin je crois) manquantes à TStaticTextEx à l' ouverture de la fiche.
- Dans ta conclusion, tu dis ... non, pas la ligne "Vive la POO" l' autre: "... quand ils doivent installer de nouveaux composants juste pour tester une application écrite par d' autres". Si je me rapelle, il y avait une source qui utilisait un compo genre TSpinEdit. J' avais laissé un message à celui qui a posté la source pour qu' il remplace le compo utilisé par un TSpinEdit pour eviter d' aller chercher le source du compo sur le net et de devoir l' installer. Maintenant que je viens donc de lire le fichier pdf, il me semble que ta méthode ne nous permettra pas de se passer de l' unit du compo original étant donné que, dans les Uses, nous devons déclarer  l' unité du compo original qui est, dans ton exemple StdCtrls. Je dis ça parce que seulement apres tu fais:
type
  TStaticText = class(StaticTextEx.TStaticText);
Donc je pense, vu aussi qu' à l' ouverture de la form, les nouvelles propriétes n' apparaissent pas (se sont celles de StaticText de l' unité StdCtrls), que l' on a besoin de l' unité du compo original. Faudrait essayer avec un autre compo qui ne serait pas dans StdCtrls pour verifier ça ...

signaler à un administrateur
Commentaire de MAURICIO le 17/01/2005 14:55:18

Quand je dis:
"Ça a l' avantage de pouvoir utiliser les 2 class et le systeme ajoutera les propriétés/events automatiquement (enfin je crois) manquantes à TStaticTextEx à l' ouverture de la fiche. "
Je voulais dire:
"Ça a l' avantage de pouvoir utiliser les 2 class et le systeme ajoutera les propriétés/events automatiquement (enfin je crois) manquantes aux compos de type TStaticTextEx à l' ouverture de la fiche. "

signaler à un administrateur
Commentaire de jmp77 le 17/01/2005 17:39:25

Hello DelphiProg,

Super Sourçe mais vu l'auteur je m'en serais douter.

Deja avec ta réponse sur le forum c'était clair mais alors maintenant c'est super fluide.
Honnetement plutot que de creer ces compos puis obligé tout le monde a les installé pour tester ta source au moins avec cette méthode c'est bien plus pratique. Biensure il ne faut pas en abuser et être prudent.

Enfin Merci à toi DelphiProg qui arrive toujours a nous apprendre des choses super interessantes.

Note finale sans appel 10/10.

Bonne prog,
JMP77.

signaler à un administrateur
Commentaire de delphimaniac le 17/01/2005 18:12:08

Hello DelphiProg,

très bonne source, très interessante. Mais comme le dis jmp77, il faut quand même réfléchir à son utilisation. Dans le cas effectivement de tests d'une application qui utilise un composant qu'on a pas, ou dans le cas d'une utilisation bien particulière d'un composant à un endroit donné, sachant qu'on en aura pas l'utilité ailleurs, je suis d'accord. Par contre dès qu'il peut y avoir ré-utilisation potentielle, je penses qu'il faut impérativement revenir à la méthode classique du composant. En fait c'est une question de volume, modifier deux ou trois unités comme cela n'est pas trop génant, mais penser à le faire à chaque fois qu'on utilise un composant de cette façon, et surtout si on l'utilise souvent, cela devient contraignant.

En attendant, merci pour ce tuto qui est vraiment très clair.

Delphimaniac

signaler à un administrateur
Commentaire de Delphiprog le 17/01/2005 20:05:10 administrateur CS

Mauricio : les propriétés/évènements n'apparaissent pas et ne peuvent pas apparaître dans l'inspecteur d'objet pour une simple raison : le composant n'est pas enregistré dans Delphi.
Le fait de déclarer en section publiée est sans influence au niveau de l'inspecteur d'objets dans ce cas.

En revanche, on peut y trouver un avantage dans le cas où l'on veut que ces propriétés soient enregistrées automatiquement quand on utilise des fonctions comme WriteComponentRes, WriteComponentResFile qui sauvegardent dans le stream toutes les propriétés publiées. C'est ce que fait Delphi avec les fichiers DFM des fiches.

En résumé, ajouter des propriétés publiées à un composant existant doit avoir un objectif bien précis et justifié.
Cette conclusion rejoint donc tout à fait les propos de Delphimaniac.

Je suis heureux que même les experts sur ce forum aient trouvé un intérêt à ce tuto.

signaler à un administrateur
Commentaire de MAURICIO le 18/01/2005 11:59:20

Je l' ai bien compris DelphiProg.
C' est d' ailleurs ce que je dis dans mon commentaire!
Mais ça répond pas à mes 2 questions, désolé ou alors g pas tout pigé.

signaler à un administrateur
Commentaire de MAURICIO le 18/01/2005 18:53:00

Ok, cette fois g compris et c' est gràce à JulioDelphi qui a bien voulu perdre son temps à m' expliquer :
on a besoin du source du compo mais on a pas besoin de l' installer. Merci Merci ...

signaler à un administrateur
Commentaire de Delphiprog le 18/01/2005 20:56:31 administrateur CS

Euh...non, on a pas besoin du source non plus. Il suffit juste d'avoir l'unité. Comment fait Delphi pour retrouver les propriétés/événements/méthodes dans l'édition personnelle puisque cette mouture n'est pas livrée avec les codes sources mais des .DCU à la place.

signaler à un administrateur
Commentaire de MAURICIO le 19/01/2005 10:10:28

oui exact!

signaler à un administrateur
Commentaire de jihelb le 20/01/2005 09:51:21

BRAVO Delphiprog pour ton didacticiel ! (10/10)
J'ai appris une chose qui m'aurait rendu de grands services par le passé, et qui m'ouvre des horizons.
Je ne suis par contre pas certain d'avoir bien compris ta conclusion (contrairement à tous j'ai bien peur)
"... quand ils doivent installer de nouveaux composants juste pour tester une application écrite par d'autre."
Celà signifie-t-il qu'au lieu d'installer l'unité TrucUnit contenant le composant TrucCompo, il suffit de rajouter dans l'unité où TrucCompo est utilisé la ligne alias (et de rajouter dans le FormCreate les lignes pour les éventuels Onxxxxxx) ?

signaler à un administrateur
Commentaire de MAURICIO le 16/04/2008 17:30:44

Salut DelphiProg,
après avoir fait quelques compos c' est beaucoup plus simple de comprendre ton tuto :)

Comme j' en ai eu besoin et que je fais légèrement differemment (en plus simple), voilà comment j' ai procédé :

J' ai un compo appelé TcyDBGrid dans mon unité cyDBGrid qui permet entre autre la gestion du MouseWheel et permet de cacher les ScrollBars gràce aux sources déposées sur CS:

type
  TcyDBGrid = class(dbgrids.TDBGrid)
    private
etc ...

à la fin de la déclaration du compo, je déclare ceci:
  TDBGrid = class(tcyDBGrid);
// Déclarer une nouvelle class TDBGrid pour que les compos dbgrid.TDBGrid déjà utilisés dans vos appli aient les mêmes options!

Comme tu peux le voir, mon compo n' a pas besoin de s' appeler TDBGrid.

Ensuite, dans mes applis cette fois, il ne me reste plus qu' à mettre dans les Uses le nom de l' unité de mon compo sans rien faire d' autre:
Uses classes, windows, dbgrids, etc ..., cyDBGrid;
Le compilateur semble aller chercher la Class TDBGrid dans mon unité cyDBGrid car c' est la dernière à être déclarée dans les Uses.

Pas besoin donc de déclarer une class TDBGrid héritant de cyDBGRid.TcyDBGrid! dans toutes les forms de mes applis.

Le mouseWheel est très bien géré mais par contre j' ai une erreur lorsque j' utilise l' option pour cacher les ScrollBars: l' erreur survient en fermant mon appli seulement: "control DBGrid2 has no parent window"

Voici mon unité :
unit cyDBGrid;

interface

uses Classes, Windows, Grids, DBGrids, Messages;

type
  TMouseWheelMode = (mwDoNothing, mwNavigate, mwSelect);

  TcyDBGrid = class(dbgrids.TDBGrid)
    private
      FOnSelectCell: TSelectCellEvent;
      FSauvDBGridWndProc: TWndMethod;
      FHorizontalScrollBar: Boolean;
      FVerticalScrollBar: Boolean;
      FMouseWheelMode: TMouseWheelMode;
      procedure SetHorizontalScrollBar(const Value: Boolean);
      procedure SetVerticalScrollBar(const Value: Boolean);   // Save original WindowProc ...
    protected
      procedure Loaded; override;
      function SelectCell(ACol, ARow: Longint): Boolean; override;
      procedure cyDBGridWndProc(var Msg: TMessage);
      procedure MouseWheelDown(Sender: TObject; Shift: TShiftState;
        MousePos: TPoint; var Handled: Boolean);
      procedure MouseWheelUp(Sender: TObject; Shift: TShiftState;
        MousePos: TPoint; var Handled: Boolean);
    public
      constructor Create(AOwner: TComponent); override;
      property FixedCols;
      function CellRectX(ACol, ARow: Longint): TRect;
    published
      property Col;              // Current column
      property LeftCol;          // First displayed column
      property Row;              // Current row
      property VisibleColCount;  // Visible normal columns (Not Fixed Columns)
      property VisibleRowCount;  // Visible normal rows (Not Fixed Rows)
      // property TopRow;  Not working, return always 1 ...
      // property Selection; Not working, return always Col e Row ...

      property MouseWheelMode: TMouseWheelMode read FMouseWheelMode write FMouseWheelMode default mwDoNothing;
      property HorizontalScrollBar: Boolean read FHorizontalScrollBar write SetHorizontalScrollBar default true;
      property VerticalScrollBar: Boolean read FVerticalScrollBar write SetVerticalScrollBar default true;
      property OnSelectCell: TSelectCellEvent read FOnSelectCell write FOnSelectCell;
    end;

  TDBGrid = class(tcyDBGrid); // Déclarer une nouvelle class TDBGrid pour que les compos
                              // dbgrid.TDBGrid déjà utilisés dans vos appli aient les mêmes options!

procedure Register;

implementation

{ TcyDBGrid}
constructor TcyDBGrid.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FSauvDBGridWndProc := WindowProc;
  FMouseWheelMode := mwDoNothing;
  FHorizontalScrollBar := true;
  FVerticalScrollBar := true;

  // Mouse wheel :
  With TDrawGrid(self) do
  begin
    OnMouseWheelDown := MouseWheelDown;
    OnMouseWheelUp := MouseWheelUp;
  end;
end;

procedure TcyDBGrid.Loaded;
begin
  Inherited;
end;

function TcyDBGrid.SelectCell(ACol, ARow: Longint): Boolean;
begin
  Result := True;
  if Assigned(FOnSelectCell) then FOnSelectCell(Self, ACol, ARow, Result);
end;

function TcyDBGrid.CellRectX(ACol, ARow: Longint): TRect;
begin
  RESULT := CellRect(ACol, ARow);
end;

procedure TcyDBGrid.cyDBGridWndProc(var Msg: TMessage);
begin
  // We have to call this all the time (not just when scrollBar properties handlers changes) :
  ShowScrollBar(Handle, SB_HORZ, FHorizontalScrollBar);
  ShowScrollBar(Handle, SB_VERT, FVerticalScrollBar);

  if Assigned(FSauvDBGridWndProc)
  then FSauvDBGridWndProc(Msg);
end;

procedure TcyDBGrid.SetHorizontalScrollBar(const Value: Boolean);
begin
  FHorizontalScrollBar := Value;

  if not (FHorizontalScrollBar and FVerticalScrollBar)
  then WindowProc := cyDBGridWndProc
  else WindowProc := FSauvDBGridWndProc;

  Invalidate;
end;

procedure TcyDBGrid.SetVerticalScrollBar(const Value: Boolean);
begin
  FVerticalScrollBar := Value;

  if not (FHorizontalScrollBar and FVerticalScrollBar)
  then WindowProc := cyDBGridWndProc
  else WindowProc := FSauvDBGridWndProc;

  Invalidate;
end;

procedure TcyDBGrid.MouseWheelDown(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
  Handled := true;

  case FMouseWheelMode of
    mwNavigate:
      begin
        if DataSource.DataSet.Active
        then
          if not DataSource.DataSet.Eof
          then DataSource.DataSet.Next;
      end;

    mwSelect:
      begin

      end;
  end;
end;

procedure TcyDBGrid.MouseWheelUp(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
  Handled := true;

  case FMouseWheelMode of
    mwNavigate:
      begin
        if DataSource.DataSet.Active
        then
          if not DataSource.DataSet.Bof
          then DataSource.DataSet.Prior;
      end;

    mwSelect:
      begin

      end;
  end;
end;

procedure Register;
begin
  RegisterComponents('Cindy DB', [TcyDBGrid]);
end;

end.

A+

signaler à un administrateur
Commentaire de MAURICIO le 17/04/2008 12:50:45

Salut à tous,

j' ai compris que l' erreur venait de :
procedure TcyDBGrid.cyDBGridWndProc(var Msg: TMessage);
begin
  // We have to call this all the time (not just when scrollBar properties handlers changes) :
  ShowScrollBar(Handle, SB_HORZ, FHorizontalScrollBar);
  ShowScrollBar(Handle, SB_VERT, FVerticalScrollBar);

  if Assigned(FSauvDBGridWndProc)
  then FSauvDBGridWndProc(Msg);
end;

Alors j' ai corrigé en ajoutant ceci:
procedure TcyDBGrid.BeforeDestruction;
begin
  WindowProc := FSauvDBGridWndProc;  // Avoid overload component error ...
  Inherited;
end;

Voilà, ça marche très bien! Par contre, je comprends pas pourquoi il me donnait l' erreur citée plus haut, si quelqu' un a une idée ...

A+ et merci encore pour ton excelent tuto!

signaler à un administrateur
Commentaire de cirec le 17/04/2008 15:21:04 administrateur CS

En fait c'est simple
le windowproc est surchargé depuis la classe TComponent par toutes les classes intermédiaires jusqu'au composant final.
Et dans leurs surcharge respective si un message n'est pas à traiter car non utile, il est renvoyé au DefWindowProc :
"DefWindowProc(Handle, Message.Msg, Message.wParam, Message.lParam);"

Donc si toi en cours de route tu le modifie et tu ne le restitue pas les classes parentes ne pourront plus travailler correctement.

Qu'on me corrige si je dis une connerie ^^

signaler à un administrateur
Commentaire de MAURICIO le 17/04/2008 15:24:39

Mais j' appelle la procédure originale dans celle dont j' ai fait dévier le flux des messages!?

  if Assigned(FSauvDBGridWndProc)
  then FSauvDBGridWndProc(Msg);

Je comprends pas ...

signaler à un administrateur
Commentaire de MAURICIO le 18/04/2008 18:30:47

Je tiens à remercier publiquement Cirec pour son aide dans l' élaboration des nouvelles fonctionnalités de mon compo tcyDBGrid.
Celui-ci étant bientôt finaliser, il est normal de le publier sur CS pour en faire profiter tout le monde.

Merci à Cirec, à DelphiProg, aux Admins (qui ont pas mal de boulot) et longue vie à CS!

Ajouter un commentaire



Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,156 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.