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

Delphi Discussion :

Problème de callback avec des paramètres


Sujet :

Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2007
    Messages
    10 254
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 254
    Par défaut Problème de callback avec des paramètres
    Salut à tous, je plante le décors.

    J'ai un traitement générique qui peut être appelé par différents process. Ce traitement, avant de se terminer doit faire quelques petites choses qui, elles, sont spécifique en fonction du process appelant.Pour cela, j'utilise un système de CallBack pour que mon traitement générique appelle toujours la même méthode.

    Donc dans mon traitement j'ai quelque chose de la sorte (pas du tout sur du code, je l'ai pas sous la main, je fais de tête):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    Type
    TMyCallback = procedure() of object;
     
    TTraite = class()
      myCallback : TMyCallback;
      procedure Lance;
      .....
    procedure Lance
    begin
    ......
    If Assigned(myCallback) then myCalback;
    ......
    end;
    Dans mes process, avant de lancer mon traitement, j'ai des instructions de la sorte pour le process 1 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     procedure callbackProcess1;
     
      .....
      traite := TTraite.Create;
      traite.myCalback := callbackProcess1;
      traite.Lance;
    ...
    ou, pour le process 2
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     procedure callbackProcess2;
     
      .....
      traite := TTraite.Create;
      traite.myCalback := callbackProcess2;
      traite.Lance;
    ...
    etc ...

    Maintenant, je rajoute un nouveau process qui, lui, aura besoin de passer un paramètre à la fonction de callback
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     procedure callbackProcessEnquiquineur(toto as string);
     
      .....
      traite := TTraite.Create;
      traite.myCalback := callbackProcessEnquiquineur('Pour pas faire comme les autres');
      traite.Lance;
    ...
    Évidemment, cela ne marche pas.
    Donc pour résumer, j'ai x callback qui ne nécessitent pas de paramètres, mais là je rajoute un callback qui, lui aura un paramètre. Et peut-être qu'à l'avenir il y en aura d'autres avec potentiellement un paramètre de type différent, avec potentiellement plusieurs paramètres, etc ...

    Existe-il une solution, je sais pas peut-être un système de paramètres optionnels de type génériques, un tableau de variant peut-être, je sais pas
    où je dois accepter de me dépanner avec une vilaine variable globale à la place du paramètre ?
    C'est bien plus simple, mais c'est pas propre

    Et j'ai oublié l'essentiel : DELPHI 6

  2. #2
    Membre Expert Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Par défaut
    Dans ces situations, en général, j'utilise la technique windows : LParam;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TMyCallback = procedure(LParam: Pointer) of object;
    Avec ca tu mets ce que tu veux dedans, l'important c'est que l'appelant et l'appelé soient d'accord sur le contenu de ce pointeur.

  3. #3
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 938
    Billets dans le blog
    6
    Par défaut
    Ou passer un array of const (TvarRec) comme dans la fonction Format ; voir ici.
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  4. #4
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 094
    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 094
    Par défaut
    Tu confonds l'appel du CallBack et le passage de l'adresse du CallBack

    Si tu dois gérer des paramètres polymorphes, le mieux serait de passer un TObject
    Avec les opérateurs is et as tu pourras facilement récupérer ton objet (ou ni si tu n'as pas besoin d'exploiter la valeur)

    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
    Type
    TMyCallback = procedure(Data: TObject) of object
     
    TTraite = class()
      myCallback : TMyCallback;
      myCallbackContext: TObject;
      procedure Lance;
      .....
    procedure Lance
    begin
    ......
    If Assigned(myCallback) 
      then myCalback(myCallbackContext);
    ......
    end;

    Dans ce code tu as confonds l'appel callback (ci-dessus) et le passage d'adresse

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
      traite := TTraite.Create;
      try
        traite.myCallbackContext:= TEnquiquineur.Create('Pour pas faire comme les autres');
        try
          traite.myCallback := callbackProcessEnquiquineur; // Ici tu avais confondu appel et passage de l'adresse
          traite.Lance();
        finally
          traite.myCalbackObjet.Free();
        end;
      finally  
        traite.Free();
      end;
    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

  5. #5
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut
    je suis d'accord avec Shai

    sinon avec les fonctions anonymes il est aussi possible de s'en sortir

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    type
      TCallBack = reference to procedure;
     
    var
      p1: Integer;
    begin
      appel(procedure begin ShowMessage('pas de paramètre'); end);
      appel(procedure begin ShowMessage('paramètre = toto en dur'); end);
      appel(procedure begin ShowMessage('paramètre capturé = ' + IntToStr(p1)); end);
    end;
    dans ce contexte, la variables sont "capturées", ce qui est aussi source de joyeux bugs quand c'est mal utilisé
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  6. #6
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2007
    Messages
    10 254
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 254
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Tu confonds l'appel du CallBack et le passage de l'adresse du CallBack
    C'était voulu, c'était pour montrer que cette procédure là nécessitait un paramètre contrairement aux autres.

    Avec ton code, je dois modifier toutes mes procédures pour qu'elles acceptent un paramètre et pour qu'elles soient conforme à la signature du callback.
    A moins que je puisse faire un appel du genre ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    If Assigned(myCallback) then 
      if Assigned(myCallbackContext) then myCalback(myCallbackContext) else myCalback;

  7. #7
    Membre extrêmement actif
    Avatar de skywaukers
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2005
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 219
    Par défaut
    Bonjour,

    peut-être en définissant des classes qui hériteraient de TTraite, en déclarant la procédure Lance Virtual chaque classe "héritière" pourraient la compléter avec l'appel de la méthode spécifique qui serait définie à son niveau.

    @++
    Dany

  8. #8
    Membre Expert Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Par défaut
    Effectivement, j'ai regardé un peu trop vite ton problème.
    J'aurai un petit penchant pour la solution de Paul, mais en D6, tu peux oublier les fonctions anonymes
    Avec ton code, je dois modifier toutes mes procédures pour qu'elles acceptent un paramètre et pour qu'elles soient conforme à la signature du callback
    Dans tout les cas tu va devoir y passer, ta callback a un type qui ne correspond pas a ton enquiquineur, donc
    soit tu met un contexte comme le propose judicieusement Shai,
    soit tu met un string en parametre, qui ne sera pas utilisé par les autres callbacks
    soit tu utilise une variable globale (un peu crade, mais te permet de garder la signature de ta fonction)
    NB : c'est cette dernière technique que j'utilise pour trier une TList de manière paramétrable, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var
    ___FSortDistancePoint___: TPoint;
    function SortDistancePoint(i1, i2: TObject): integer;
    begin
      Result := CompareValue(Dist(TCercle(i1).centre, ___FSortDistancePoint___), Dist(TCercle(i2).centre, ___FSortDistancePoint___));
    end;
    ...
     
    ___FSortDistancePoint___ := Point(10,15);
    MonObjectlist.sort(SortDistancePoint);

  9. #9
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 094
    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 094
    Par défaut
    Citation Envoyé par sevyc64 Voir le message
    C'était voulu, c'était pour montrer que cette procédure là nécessitait un paramètre contrairement aux autres.

    Avec ton code, je dois modifier toutes mes procédures pour qu'elles acceptent un paramètre et pour qu'elles soient conforme à la signature du callback.
    A moins que je puisse faire un appel du genre ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    If Assigned(myCallback) then 
      if Assigned(myCallbackContext) then myCalback(myCallbackContext) else myCalback;
    Si tu as la flemme de faire le refactoring de masse

    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
    Type
      TMyCallback = procedure() of object;
      TMyCallbackWithContext = procedure(Data: TObject) of object;
     
    TTraite = class()
      myCallback : TMyCallback;
      myCallbackWithContext: TMyCallbackWithContext ;
      myCallbackContext: TObject;
      procedure Lance;
      .....
    procedure Lance
    begin
    ......
     if Assigned(myCallbackWithContext) and Assigned(myCallbackContext) then
         myCallbackWithContext(myCallbackContext) 
     else if Assigned(myCallback) then 
         myCalback;
    ......
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
      traite := TTraite.Create;
      try
        traite.myCalback := callbackProcess2;
        traite.Lance;
      finally  
        traite.Free();
      end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    traite := TTraite.Create;
      try
        traite.myCallbackContext:= TEnquiquineur.Create('Pour pas faire comme les autres');
        try
          traite.myCallbackWithContext := callbackProcessEnquiquineur; // Ici tu avais confondu appel et passage de l'adresse
          traite.Lance();
        finally
          traite.myCalbackObjet.Free();
        end;
      finally  
        traite.Free();
      end;
    En fait, tu fais des classes avec des évènements, en général, j'utilise par défaut un TNotifyEvent, c'est le type minimale que j'utilise
    Si j'ai besoin de spécialiser, je ne me gène pas à faire des évènements spécifiques !
    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

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 05/07/2007, 14h24
  2. [ADO/Access] Appel d’une requête avec des paramètres
    Par Taxenna dans le forum Bases de données
    Réponses: 1
    Dernier message: 07/12/2004, 14h58
  3. Réponses: 6
    Dernier message: 19/10/2004, 13h46
  4. Erreur sur une fonction avec des paramètres
    Par Elois dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 05/05/2004, 21h00
  5. créer un noeuds avec des paramétres
    Par Toxine77 dans le forum XMLRAD
    Réponses: 5
    Dernier message: 21/01/2003, 16h11

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