DeltaFX
Messages postés449Date d'inscriptionlundi 19 avril 2004StatutMembreDernière intervention 8 avril 2009
-
19 juil. 2006 à 10:25
cs_Forman
Messages postés600Date d'inscriptionsamedi 8 juin 2002StatutMembreDernière intervention 6 avril 2010
-
30 juil. 2006 à 19:59
Yo,bande de coderz,
Je me pose un question : j'ai un prog qui utilisele TcyPictureArea de Mauricio, et pour résumer (pour ceux qui connaissent pas), ce composant permetde définir des zones clickables dans une image. Si je clique sur une de ces zones, le compo me retourne l'index de la zone cliquée (via la fonction areaclick). Evidement derriere, j'ai un case AreaIndex of..... et c'est là que ca me turlupine.
Plutot que ce case of ne pourrais-je pas utiliser un array of procedure et utiliser AreaIndex pour exécuter directement telle procedure ?
Je rame un peu pour mettre cette idée en pratique.... z'auriez des idées / bout_de_codes / exemples ?
cs_Forman
Messages postés600Date d'inscriptionsamedi 8 juin 2002StatutMembreDernière intervention 6 avril 20101 19 juil. 2006 à 22:33
Pour compléter ce que vient d'expliquer CptPingu, je rajoutterais:
il y a 2 "sortes" de types pour les procédures/fonctions:
* Ceux décrits précédemment (c'est à dire les procédures et fonctions classiques, qui ne sont pas des méthodes de classes)
* Les méthodes d'objets. La déclaration de leur type est suivie de la directive "of object", par exemple:
var
OnClick : Procedure(Sender: TObject) of object;
ceci signifiera que la variable OnClick pourra recevoir une méthode d'un objet qui a les même paramètres. Par exemple:
type
TStupidClass=class
procedure ClickMe(Sender:TObject);
end;
A noter que les procédures "standards" et les procédures "of object" ont des types qui sont incompatibles entre eux, même si la liste des paramètres est la même. La taille mémoire d'une procédure standard est 32 bits (tout simplement la taille d'un pointeur) alors qu'une procédure "of object" occupe 64 bits: 32 bits pour un pointeur vers l'instance de l'objet qui possède la méthode et 32 bits pour le pointeur vers l'adresse de la procédure.
Concrètement, une procédure "of object" a la déclaration équivalente au type TMethod (qui d'ailleurs est déclaré dans Sysstem.pas):
type
TMethod = record
Code, Data: Pointer;
end;
Code est le pointeur vers la procédure et Data doit contenir une instance de l'objet qui possède la procédure.
Les autres directives dans la déclaration d'une procédure/fonction telles que stdcall, cdecl et autres sont aussi prises en compte dans la compatibilité des types fonctionnels entre eux. Par contre, le nom des paramètres n'est pas important, à condition que les types soient les même. Par exemple:
les 3 types suivants ne sont pas équivalents:
type
TIdioticType1=function(x,y:Integer):Integer;
TIdioticType2=function(x,y:Integer):Integer;stdcall;
TIdioticType3=function(x,y:Integer):Integer of object;
les 2 types suivants sont équivalents:
type
TSmartType1=procedure(p:Pointer);
TSmartType2=procedure(q:Pointer);
DeltaFX
Messages postés449Date d'inscriptionlundi 19 avril 2004StatutMembreDernière intervention 8 avril 20092 26 juil. 2006 à 15:03
Re question sur le meme sujet: j'ai bien capté je crois, mais héhéhé ca m'arrange pas trop d'avoir a typer fortement. Je m'explique, vu qu'il s'agit d'une interface utilisateur certains boutons appelle des procedures avec ou sans paramètres, d'autres des functions.....
Donc y a t'il moyens de déclarer un "Array of procedure or function" en restant "générique" sans déclarer un type particulier ?
Vous n’avez pas trouvé la réponse que vous recherchez ?
cptpingu
Messages postés3837Date d'inscriptiondimanche 12 décembre 2004StatutModérateurDernière intervention28 mars 2023123 26 juil. 2006 à 15:34
Non, ca reviendrait à créer un tableau contenant différent type de donnée,ce qui n'est pas possible. Il te reste la solution de faire un "array of pointer", mais non seulement tu devra transtyper à chaque fois ce pointeur, mais en plus tu devra trouver un moyen de récupérer le bon type à chaque fois...
Derniere solution, pas très élégante:
Tu ne créer que des fonctions, ayant toute le meme nombres de parametres. Certaines fonctions auront donc des parametres inutiles, et pour les procedures il suffira d'utiliser les fonctions sans récupérer le résultat. C'est bien moche, mais ca pourrait marcher.
cs_Forman
Messages postés600Date d'inscriptionsamedi 8 juin 2002StatutMembreDernière intervention 6 avril 20101 26 juil. 2006 à 21:07
Il y a peut-être une autre solution, peut-être plus élégante. Je ne sais pas exactement ce que tu comptes faire dans ton programme, mais pense à utiliser les messages. Je m'explique:
procedure TMsgClass.HandleMsg1(var Message:TMsg1);
begin
ShowMessage(Message.Text);
end;
procedure TMsgClass.HandleMsg2(var Message:TMsg2);
begin
Message.Result:=Message.x+Message.y;
end;
Une fois que tu as écrit ça, tu peux faire les appels suivants:
var
Msg1:TMsg1;
Msg2:TMsg2;
MsgClass:TMsgClass;
begin
MsgClass:=TMsgClass.Create;
Msg1.Msg:=MsgID1;
Msg2.Text:='Salut monde';
MsgClass.Perform(Msg1); //Appelle "HandleMsg1"
Msg2.Msg:=MsgID2;
Msg2.x:=1;
Msg2.y:=2;
MsgClass.Perform(Msg2); //Appelle "HandleMsg2" et calcule x+y et le stocke dans Result
end;
La méthode Perform se charge de "distribuer" le message à la bonne méthode (en fonction de la directive "message xxxxxx" dans les déclarations). Les 4 premiers octets de la structure passée en paramètre à Perform sont utilisés pour comparer les identifiants de messages. Cette méthode permet de passer des paramètres quelconques à un ensemble de méthodes.
Il faut toutefois noter que les contrôles Delphi ont déjà des messages réservés à des usages bien précis. Si tu comptes utiliser des messages avec des descendants de TControl, il ne faut pas utiliser les identifiants compris entre 0 et WM_USER (constante déclarée dans Messages.pas)
DeltaFX
Messages postés449Date d'inscriptionlundi 19 avril 2004StatutMembreDernière intervention 8 avril 20092 30 juil. 2006 à 18:58
Le compo de mauricio TcyPictureArea permet de découper une image en zones cliquables, mais ne crée pas d'evenement OnClick à chaque zone. Via Le Onclick du composant, on a AreaIndex qui renvoie l'index de la zone cliquée, charge au concepteur de faire un Case AreaIndex of pour savoir quoi faire dans tel cas.
Le but est de voir si "MyProcedureArray[AreaIndex]" est plus rapide que ce "case of".
Je suis adepte du "pourquoi faire simple quand on peut faire compliqué", mais j'aime pas multiplier les entités ad lib pour le plaisir.
cs_Forman
Messages postés600Date d'inscriptionsamedi 8 juin 2002StatutMembreDernière intervention 6 avril 20101 30 juil. 2006 à 19:59
Les méthodes avec messages sont très rapides en tout cas, la routine Dispatch est programmée en assembleur pour appeler le bon "handler" en fonction du message, et on peut voir son code dans System.pas. Je pense qu'elle a une rapidité équivalente à case...of.
Je pense que pour un nombre réduit de cas possibles, case of est le plus rapide, et s'il y a beaucoup de procédures différentes alors MyProcedureArray[AreaIndex] sera le plus rapide.
En effet, au niveau du code machine généré, case of ... end teste toutes les possibilités les unes après les autres, et va directement à l'adresse du code concerné dès qu'il a trouvé une valeur qui correspond (cette adresse n'ayant pas à être calculée puisqu'elle est définie statiquement dans le programme).
Avec un tableau de procédures, le code doit déjà lire une adresse dans une case indicée du tableau (ce qui n'est pas très rapide par rapport à un test par exemple, en effet, il doit y avoir un accès à la RAM pour lire la valeur et l'amener dans les registres du processeur) et aller à cette adresse. Cette méthode devient plus rapide que la précédante lorsque le nombre de cas possible à tester dans le case ... of donne un nombre de tests assez grand pour que ça prenne plus de temps que de lire l'adresse dans le tableau.
On pourrait imaginer une méthode de case...of améliorée en faisant une dichotomie (il faudrait la programmer en assembleur). Par exemple, s'il y a 8 zones dans l'image (numérotées de 0 à 7):
if AreaIndex>=4 then begin
if AreaIndex>=6 then begin
if AreaIndex=7 then
Procedure7
else
Procedure6
end else begin
if AreaIndex=5 then
Procedure5
else
Procedure4
end;
end else begin
if AreaIndex>=2 then begin
if AreaIndex=3 then
Procedure3
else
Procedure2
end else begin
if AreaIndex=1 then
Procedure1
else
Procedure0
end;
end;
Je pense qu'il est évident que cette méthode peut être généralisée à d'autres cas.
Avec cette méthode, il y a Log(n)/Log(2) (ici 3) tests consécutifs pour appeler la bonne procédure, avec un case...of il y a en moyenne n/2, si on appelle n le nombre de valeurs possibles de AreaIndex. Et pour n grand, Log(n)/Log(2) est très petit par rapport à n/2...