begin process at 2013 05 26 06:33:04
  Trouver un code source :
 
dans
 
Accueil > 

Tutoriels

 > 

Tutoriaux

 > COMMENT UTILISER UN FORMULAIRE SANS AVOIR BESOIN DE LE DÉCLARER DANS LE USES - TUTORIEL SUR LES INTERFACES ET LA POO

COMMENT UTILISER UN FORMULAIRE SANS AVOIR BESOIN DE LE DÉCLARER DANS LE USES - TUTORIEL SUR LES INTERFACES ET LA POO


 Information sur le tutoriel

Note :
Aucune note

 Description

Bonjour à tous,
Dans le cadre du développements de nos applications modulaires (avec BPL), un ami à moi m'a demandé (afin d'éviter des appels récursifs entre packages et autres sources) de pouvoir appeler un formulaire sans connaître son unité .pas, il existe plusieurs méthodes pour cela, mais je vous présente ici une méthode simple, rapide et efficace et également sans trop
de sources à développer. Grâce à ce projet, vous allez pouvoir appeler vos classes sans avoir à les déclarer dans vos uses. Ce petit projet est une partie d'un projet complet permettant de développer rapidement des applications sans avoir à développer (ou également en développant suivant le cas). C'est un projet permettant de déployer des applications rapidement et les modifier directement chez le client sans re compilation complète. Mais ceci est une autre histoire :)

pour les sources consultez mes sources - tutoriel - interface
http://www.delphifr.com/code.aspx?ID=54392

Tutorial

Comment se passer d'une référence pour appeler un objet défini dans cette dernière ?


Soit 2 unités, l'une contient un objet et l'autre veut appeler cet objet sans faire de use de la première. Pourquoi ? Imaginez que la première unité contient déjà des dizaines de références à d'autres unités. Le fait d'ajouter l'unité de l'objet obligera obligatoirement d'ajouter soit les chemins d'accès, soit carrément les dites unités à notre projet. Ce qui aura pour effet de gonfler considérablement notre application alors qu'on a besoin que d'une petite partie.

Pour cela 2 méthodes simples peuvent nous servir.

RegisterClass et getClass

Si l'on reprend la définition de l'aide de Delphi, RegisterClass Recense une classe d'objet persistant pour que le type de classe puisse être retrouvée. Et GetClass, Renvoie une classe persistante recensée à partir de son nom de classe.

Grâce à ces 2 méthodes, nous allons pouvoir résoudre notre problème.

L'exemple Delphi fourni va faire appel à cette méthode pour créer un formulaire sans avoir besoin de faire référence à ce dernier. Tout simplement en appelant GetClass (' MonFormulaire '). Dans l'exemple on utilise également une interface pour permettre un partage mémoire de la classe, mais on peut très bien s'en passer. Voici cependant le synopsis du projet.

L'unité intUnit contient l'ensemble des méthodes de partage, chaque fois que l'on veut partager un objet et faire appel à ce dernier dans l'ensemble d'un projet, il suffit de faire un uses sur cette unité et rien d'autre. Cette unité sert donc d'interface car elle doit également être placée dans les autres unités que l'on veut partager.

intUnit contient une interface de partage nommée IInterfacedObject .

/// < summary >
/// interface permettant d'avoir un objet unique en mémoire, qui peut être partagé
/// par plusieurs modules ou applications
/// </ summary >
IInterfacedObject = interface ( IInterface )
[ '{B7CE8FC8-D0AC-49F5-BD74-0BE69FF811EC}' ]
// placer ici les méthodes voulant être partagée
procedure ShowForm ;
procedure SendMessage ( const msg : string );
end ;

Cette interface sera notre référence mémoire dans tous les projets pour appeler notre formulaire

intUnit contient également la méthode GetObject pour instancier notre interface

/// < summary >
/// méthode d'appel du formulaire
/// cette méthode est celle à partager dans tous les modules ou l'on souhaite créer sans se lier aux unités
/// < param name =' className : string'>nom de la classe à instancier</ param >
/// </ summary >
function GetObject ( const className : string ): IInterfacedObject ;

Et nous avons enfin, la méthode

/// < summary >
/// méthode permettant d' instancer une classe de n' importequel type
/// < param name =' Aowner : TComponent '>objet parent de la classe à instancier, peut être à NIL</ param >
/// < param name =' InstanceClass : TComponentClass '>
/// < param name =' Reference : non typé'>paramètre de sortie, permettant d'instancier une classe sans avoir besoin de son type</ param >
/// </ summary >
procedure InstancyComponent ( Aowner : TComponent ; InstanceClass : TComponentClass ; var Reference );

Nous avons également une unité uForm2 qui sera notre formulaire parent un TForm interfacé avec IInterfacedObject

TForm2 = class ( TForm , IInterfacedObject )
Memo1: TMemo ;
private
{ Déclarations privées }
public
{ Déclarations publiques }
procedure ShowForm ;
procedure SendMessage (const msg : string);
end ;

2 méthodes test sont donc interface dans ce formulaire, ShowForm et SendMessage , une classe interfacée doit obligatoirement contenir les thod es définies dans l'interface.

Nous avons ensuite une unité uForm3 qui hérite elle de uForm2 et donc de toute ces méthodes. C'est elle que l'on va appeler sans ajouter de uses uForm3 dans notre unité d'appel. Pour qu'elle soit connue de l'ensemble du programme, on appel la méthode RegisterClass (TForm3) dans l'initialisation de l'unité uForm3 . Et nous appelons UnRegisterClass (TForm3) dans la finalisation de l'unité dès que l'on quitte le programme.

Enfin dans notre unité principale, uMain , on fait simplement appel à intUnit pour créer TForm3

// vous remarquerez qu'on ne libère pas une interface, le programme s'en charge tout seul
procedure TForm1.Button1Click(Sender: TObject );
begin
// supprimez simplement ce test si vous voulez plusieurs interface, ici, on n'affiche qu'une seule form
if Formulaire= nil then
begin
// je veux par exemple une instance de TForm3 défini e dans uForm3, remarquez qu'on n e fait pas appel à uForm3 dans les uses :)
Formulaire:= GetObject ('TForm3' );
if Formulaire <> nil then // si on a réussie à instancier TForm3 on appel la méthode partagée ShowForm
Formulaire.ShowForm ;
end;
end;


Commentaires

Commentaire de cirec le 01/10/2012 11:53:00 administrateur CS

Salut,

je suis au regret de vous informer que ceci est faux !!!

en utilisant cette méthode, l'unité en question est déclarée deux fois dans le *.dpr !!!
donc déjà on ne gagne rien bien au contraire nous ajoutons de l'inutile.

ensuite en ce qui concerne la libération ... on ne libère pas une interface ... ok
mais le formulaire qui y est associé lui doit être libéré ... mais ce n'est pas le cas ici !
bonjour les fuites de mémoire.

Commentaire de Keneda le 01/10/2012 14:39:25

Bonjour administrateur CS,
très intéressant ce que vous racontez là,
avez-vous des exemples concrets et test mémoire pour expliquer cela ? :)

Le but ici n'est pas de faire le malin (pour moi je parle) mais bel et bien de montrer le mode opérateur
à savoir ce qu'est une interface et comment l'utiliser.

De plus, je ne vois pas ce dont vous voulez parler quand vous dites "l'unité est déclarée 2 fois dans le dpr" ???
la déclaration n'est nullement un appel, vous n'avez semble-t-il rien compris au principe du tutoriel, ici, on parle bien d'un appel depuis une autre unité
si vous connaissez le développement par paquet (ce que je doute vu votre commentaire) vous comprendrez l'intérêt de cet appel quand on se retrouve avec une application ou les appels se croisent et se recroisent (cas d'application des 90 style ERP monumentale à débugger)

Merci toute fois pour votre critique non constructive selon moi car elle démarre directement par un contre argument....
Administrateur CS........... hmmmm voyons voir C# ? ok je comprend mieux ;)

Commentaire de Keneda le 01/10/2012 14:57:07

oups, je viens de voir, ce n'est pas administrateur CS, mais CIREC désolé, moi aussi tout comme vous, je lit entre les lignes
et me fait des idées un peu trop hative ;)

Commentaire de cirec le 02/10/2012 01:09:10 administrateur CS


bon,

1°) à aucun moment je n'ai mis en doute tes capacités en programmation, contrairement à toi!!!
  mais si c'est ce que tu veux, je prends le bâton que tu me tends.
2°) ce n'est pas une critique mais une constatation
et il ne faut pas sortir de Saint-Cyr pour constater ce qui suit.
Le titre dit:
"COMMENT UTILISER UN FORMULAIRE SANS AVOIR BESOIN DE LE DÉCLARER DANS LE USES"

plus loin on peut lire:
"Grâce à ce projet, vous allez pouvoir appeler vos classes sans avoir à les déclarer dans vos uses."

... je regarde le code et je constate que c'est faux !!!
dans les uses du dpr on trouve
intUnit
uForm2 avec son dfm
uForm3 avec son dfm

donc pour éviter une déclaration dans les "uses" pour utiliser uForm3, il faut 3 unités à la place d'une seule ... belle économie oui!
que tu le veuilles ou non ceci augmente la taille de l'exécutable
donc l'argument suivant tombe aussi (à savoir éviter le gonfler considérablement notre application)

3°) pour les fuites de mémoires (voici le détail):

---------------------------
Unexpected Memory Leak
---------------------------
An unexpected memory leak has occurred. The unexpected small block leaks are:
1 - 12 bytes: Unknown x 1
13 - 20 bytes: TList x 4, Unknown x 4
21 - 28 bytes: TIconImage x 1, TBrush x 3, UnicodeString x 2
29 - 36 bytes: TMemoStrings x 1, TPen x 1, TMargins x 2, TPadding x 2, TSizeConstraints x 2, Unknown x 3
37 - 44 bytes: TFont x 3
45 - 52 bytes: TGlassFrame x 1
53 - 60 bytes: TIcon x 1
69 - 76 bytes: TControlScrollBar x 2
101 - 108 bytes: TControlCanvas x 1
149 - 156 bytes: Unknown x 1
621 - 668 bytes: TMemo x 1
877 - 956 bytes: TForm3 x 1
---------------------------
OK  
---------------------------
*** pour information ***
depuis Turbo Delphi Explorer l'IDE est doté d'un outil permettant de traquer les fuites de mémoire.
Pour l'activer il suffit d'ajouter cette ligne:
  ReportMemoryLeaksOnShutdown := True;


4°) ensuite tu dis:
"Le but ici n'est pas de faire le malin (pour moi je parle) mais bel et bien de montrer le mode opérateur
à savoir ce qu'est une interface et comment l'utiliser ..."
Un tutoriel ce n'est pas un simple code que l'on soumet à communauté c'est une leçon ... quand on dépose un tutoriel
on est supposé en maitriser un minimum le sujet.

"si vous connaissez le développement par paquet (ce que je doute vu votre commentaire) ..."
"Merci toute fois pour votre critique non constructive selon moi car elle démarre directement par un contre argument....
Administrateur CS........... hmmmm voyons voir C# ? ok je comprend mieux ;)"

je vois bien que je t'ai vexé ... si tu le prends comme ça ... bah tant pis !
à en croire ce que tu écris tu es Développeur professionnel ...
ce que vous bricolez dans votre boite ne me regarde pas
quand à débugger vos applications ... quand je vois déjà le "bordel" dans ce bout de code ... ben non merci!!!

Si tu arrives à "enfumer" ton chef de projet et ton boss avec ce genre de code tant mieux pour toi
mais chez moi ça passe ne pas et je plains vos clients

ps: " Aowner : TComponent objet parent de la classe à instancier,"
l'Owner n'est pas le parent .. à ne pas confondre
l'Owner c'est l'hôte ... celui qui se charge de la destruction de l'objet

voilà t'as eu ce que tu voulais !!

Commentaire de Keneda le 03/10/2012 10:27:26

Cirec,
de une tu ne me vexe pas du tout, j'ai bien d'autres chats à fouetter pour m'occuper de ce genre de reflexion,
de deux, je confirme que tu n'as rien compris au but de ce tutoriel, le fait de le commencer par ceci est totalement FAUX !!!
n'est franchement pas une critique constructive et il semble sérieusement que tu n'as pas lu et compris le projet :)))
je t'explique comme un néohpyte....

  tu as un projet (ici c'est un exemple en DPR pour montrer le code donc pas un cas concret. donc oublie ton histoire d'appel multiple ça vaut peau de balle ;), oui désolé, je n'allais pas mettre dans mon exemple un projet complet car je sais que ceux qui lisent ce tutoriel savent de quoi je parle, oups désolé c'est pas ton cas) donc supposons que ton projet utilise plusieurs paquets de conception  (on suppose que tu connais la programmation par paquet).
  dans une application (je précise que tu n'as pas développer mais que tu reprends et que tu dois maintenir.... tu verras quand tu seras grand et que tu travailleras chez
  des pros, ça peut arriver de devoir travailler sur des projets qui ne sont pas les tiens).  (bon allez j'arrête l'ironie je n'aime pas ça)

  donc sérieusement, tu as une application par paquet dont l'un des paquet possède une unité dont tu as besoin dans un paquet de niveau supérieure. Mais cette unité fait appel
  à plusieurs autres unités....explique moi comment appeler cette unité dans ton paquet de niveau supérieure sans avoir besoin de tout déplacer (oui on est dans une application professionnelle avec des tonnes de fuites mémoires et d'autres problèmes et on ne touche pas à ce qui fonctionne (encore une fois tu comprendras que tu y sera confronter)

   Bref, je donne ici une solution, il en existe d'autres évidemment, mais désolé de te décevoir cette solution est VRAI et achie VRAI..elle fonctionne à été éprouvée et dans
   le cadre des paquets, elle fonctionne sans fuite mémoire ;)


Je ne vais pas continuer à te répondre car ce serait sans fin je pense, je ne met pas en doute tes compétences en programmation non plus, je fais juste de l'humour
sache simplement que cette solution fonctionne donc inutile de venir commencer tes critique par "c'est FAUX" et ça ne me vexe pas, je le précise je le dit objectivement
ce n'est pas constructif ;)   tu as décelé une fuite mémoire et c'est pas mal mais ce n'est que dans ce projet là :)
(oublie les appels en double car ce que tu dis là c'est du grand n'importe quoi (je fais comme toi))

Reviens me voir quand tu seras confronter à de vrais projets




  

 Ajouter un commentaire




Nos sponsors


Sondage...

CalendriCode

Mai 2013
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Photothèque

A découvrir



 
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

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,109 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales