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

C++Builder Discussion :

Pointeur de fonction, comment passer une fonction en paramètre d'une autre fonction


Sujet :

C++Builder

  1. #1
    Futur Membre du Club
    Inscrit en
    Janvier 2009
    Messages
    24
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 24
    Points : 9
    Points
    9
    Par défaut Pointeur de fonction, comment passer une fonction en paramètre d'une autre fonction
    Le programme sur lequel je travail est constitué d'un grand nombre de fonction (dans mon exemple je les nomme : fonction1, fonction2, etc..., elle renvoi un AnsiString) et à chaque fois que j'utilise l'une d'entre elle je dois calculer leurs paramètres et faire d'autre opération.
    Si j'écris ces opérations à l'appel chaque fonction, ça va me faire un code super long et répétitif.
    Comme ces opérations et calcul sont les mêmes pour chaque fonctions, j'ai envi de les mettre dans une fonction qui les ferait et appellerai la fonction qu'on lui à passé en paramètre (fonction1 ou fonction2 ou ...).


    J'ai cherché du coté des pointeurs de fonction et j'ai trouvé pas mal de chose, mais je n'ai rien réussit à faire marché. Je n'ai pas tout compris non plus, je suis débutant en pointeur.

    Voici, de façon simplifié, ce que je souhaite faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    "fonctionN" = &fonction1;  //pointeur sur la fonction qui sera passer en paramètre
    RemplirCase( a, b, "fonctionN");
     
    //----------------------------------
    void RemplirCase(int a,int b, "fonctionN")
    {
    offset=a+b;
    AnsiString data = fonctionN(offset,1);
    }
    j'ai essayé ceci pour créer le pointeur :

    .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    AnsiString __fastcall Fonction1(int offset);
    .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
       AnsiString ( *pFonction1)(int) = NULL;
    pFonction1 = &Fonction1;
    Mais j'ai une erreur à la dernière ligne : E2034 Impossible de convertir 'AnsiString (_fastcall * (_closure )(int))(int)' en 'AnsiString (*)(int)

    Quelqu'un pourrait-il m'aider?

    Merci.

  2. #2
    Membre expérimenté
    Avatar de sat83
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2004
    Messages
    1 040
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 040
    Points : 1 307
    Points
    1 307
    Par défaut
    Je n'ai pas C++ Builder sous la main, mais voilà quelquechose qui devrai fonctionner :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    //Déclaration du prototype de ta fonction qui sera passée en paramètre
    typedef void (__closure *MyParameterFunction) ( int a, int b ) ;
    //Déclaration d'une fonction dont un paramètre est un pointeur vers ta fonction déclarée précedement
    AnsiString MyFunction( int i, MyParameterFunction aFunction ) ;
    et dans le cpp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    AnsiString MyFunction( int i, MyParameterFunction aFunction )
    {
      int tmpInt = 10;
      int tmpInt2 = 10 * i ;
      aFunction( tmpInt , tmpInt2  ) ; // appel a ta fonction
    }
    Ce que l'on apprend par l'effort reste toujours ancré plus longtemps...

  3. #3
    Membre expérimenté
    Avatar de sat83
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2004
    Messages
    1 040
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2004
    Messages : 1 040
    Points : 1 307
    Points
    1 307
    Par défaut
    Un exemple sera peut etre plus explicatif :

    dans le *.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //déclaration du prototype de ta fonction
    typedef int (__closure *Operation) ( int, int ) ; 
     
    class TForm1 : public TForm
    {
    //[...]
    private:
       int Addition( int x, int y ) ; 
       int Multiplication( int x, int y ) ;
       void ExecuteFonction( int i, int j, Operation aFunction ) ; 
    };
    dans le *.cpp
    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
    int TForm1::Addition( int x, int y )
    {
      return( x+y ) ;
    }
    //------------------------------------------
    int TForm1::Multiplication( int x, int y )
    {
      return( x*y ) ;
    }
    //------------------------------------------
    void TForm1::ExecuteFonction( int i, int j, Operation aFunction )
    {
    //Execution de la fonction passée en paramètre sans la connaitre a l'avance
      int result = aFunction( i, j );
    //Affichage du résultat.
      ShowMessage( IntToStr( result ));
    }
    A l'exécution, exemple avec deux boutons, chacun faisant appel à la même méthode (ExecuteFunction) mais effectuant 2 actions différentes selon la méthode passée en paramètre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //------------------------------------------
    void __fastcall TForm1::BitBtn1Click(TObject *Sender)
    {
      ExecuteFonction( 10, 10, Addition ) ;
    }
    //---------------------------------------------------
    void __fastcall TForm1::BitBtn2Click(TObject *Sender)
    {
      ExecuteFonction( 10, 10, Multiplication ) ;
    }
    Ce que l'on apprend par l'effort reste toujours ancré plus longtemps...

  4. #4
    Membre chevronné

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 389
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 389
    Points : 1 776
    Points
    1 776
    Par défaut
    Salut !

    Si j'écris ces opérations à l'appel chaque fonction, ça va me faire un code super long et répétitif.
    Comme ces opérations et calcul sont les mêmes pour chaque fonctions, j'ai envi de les mettre dans une fonction qui les ferait et appellerai la fonction qu'on lui à passé en paramètre (fonction1 ou fonction2 ou ...).
    Tu as probablement, au niveau de ton projet, un problème de conception à résoudre !
    Parce que :

    Comme ces opérations et calcul sont les mêmes pour chaque fonctions,
    A mon avis ... il y a un problème bien avant celui de la déclaration d'un pointeur vers méthode (ou vers fonction) !

    A plus !

  5. #5
    Futur Membre du Club
    Inscrit en
    Janvier 2009
    Messages
    24
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 24
    Points : 9
    Points
    9
    Par défaut
    Merci beaucoup sat83, c'est exactement ce qu'il me fallait.

    @ henderson : En faite mon programme permet de lire et décoder des données contenues dans un fichier, le but est d'afficher ces données dans un tableau en fonction de ce que souhaite voir l'utilisateur.
    Ce fichier est constitué de 15 pages, chaque pages et constitué de 255 fiche contenant des données (un grands nombre ) toutes codées de façon différente.
    Il me faut donc une fonction par donner à décoder.
    Pour faire le décodage mes fonctions ont besoin de connaitre l'emplacement en mémoire des octets à lire, c'est ce que je calcul avant l'exécution de mes fonctions, j'ajoute également des colonnes à mon tableau à ce moment là. Ça ne prend que 10 lignes, mais 10 lignes fois le nombre de données ça fait beaucoup, c'est ce que je souhaite ainsi éviter.

    C'est pour cela que c'est répétitif. Enfin c'est un peut long à expliquer, je ne sais pas si j'ai été clair, mais je n'ai pas trouvé d'autre façon de faire.

  6. #6
    Membre chevronné

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 389
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 389
    Points : 1 776
    Points
    1 776
    Par défaut
    Salut !

    En fait ... tout dépend de l'organisation des données dans chaque fiche parmi les 255 d'une page parmi 15 pages !

    Par exemple, si les fiches reposent sur un même modèle, on peut alors imaginer un tableau de pointeurs vers fonction pour résoudre chaque champ.
    Et dans ce cas, il ne serait plus nécessaire de passer une fonction comme paramètre.
    Ce tableau étant initialisé une fois pour toutes, une simple boucle (pour traiter une fiche) suffirait pour solliciter la bonne fonction pour la bonne donnée.
    Et dans ce cas précis, on pourrait envisager de passer un pointeur vers AinsiString et un pointeur vers int pour passer d'un champ à l'autre ...

    Mais bon ... chacun fait bien comme il veut... du moment que ça fonctionne !

    A plus !

  7. #7
    Futur Membre du Club
    Inscrit en
    Janvier 2009
    Messages
    24
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 24
    Points : 9
    Points
    9
    Par défaut
    Comme je l'ai dit au départ, je suis novice avec les pointeurs et ça fait 6 mois que je fais du C++, je ne connais pas encore toute les ficelles.

    Je vais étudier les tableaux de pointeurs pour voir ce que je peux faire. Je suis au début de mon projet, je peux encore me permettre de changer de méthode de traitement, même si la mienne fonctionne, bien qu'elle me paraisse un peu lourde.

    Edit :

    Les 255 fiches sont toutes faite sur le même modèle.

    j'ai tester ceci :

    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
    AnsiString __fastcall(__closure *PtrTab[1]) ( int ) ;
     
    PtrTab[0]=MyFonction1;     //Décodage d'un type de donnée, renvoie un AnsiString
    PtrTab[1]=MyFonction2;     //Décodage d'un type de donnée, renvoie un AnsiString
    int data;
     
    //Les types de donnée sont classé et affiché dans des colonnes d'un StringGrid.
     
    for(int col=0;col<2;col++)
      {
        data=1;
        for(int row=0;row<3;row++)
          {
            StringGrid1->Cells[col][row]=PtrTab[col](data);
            data=0;
          }
      }
    Est-ce que ça correspond à ce que tu m'as dit?

  8. #8
    Membre chevronné

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 389
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 389
    Points : 1 776
    Points
    1 776
    Par défaut
    Salut !

    Tout à fait !
    J'ai bien formulé dans ce sens !
    Donc un tableau de fonctions qu'il suffit d'initialiser au départ.
    Je suppose ici un tableau de (col) pointeurs vers fonction (et non vers méthode).
    Ce tableau évite en particulier de coder un switch.
    Et au delà de ton projet, cela permet d'avoir une grande flexibilité au niveau du traitement, puisque le tableau est toujours modifiable à un moment donné... et peut donc s'adapter à d'autres combinaisons de traitements.

    A plus !

  9. #9
    Futur Membre du Club
    Inscrit en
    Janvier 2009
    Messages
    24
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 24
    Points : 9
    Points
    9
    Par défaut
    OK, mais mon problème c'est la gestion de cette table de pointeur.

    Dans mon appli, l'utilisateur sélectionne les données qu'il veut voir dans son tableau avec des CheckBox (Je vais en avoir beaucoup).
    Donc pour l'instant je traite ça comme un bourrin , de la façon suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    if(CheckBox1->Checked=true)
    {
    fonction1(...); //décodage du type donné 1, et affichage dans une colonne du tableau
    }
    if(CheckBox2->Checked=true)
    {
    fonction2(...); //décodage du type donné 2, et affichage dans une colonne du tableau
    }
    ...
    C'est facile à coder, mais c'est un peut long et pas très élégant (solution de façilité ).

    J'ai pensé à une autre solution avec un tableau de pointeur vers fonction et un tableau de pointeur vers mes checkbox, mais là je sais pas si c'est possible, j'ai tenté un truc, mais ça ne marche pas.
    Est-il possible de faire un tableau de pointeur vers des checkbox (ou autre composant)?

  10. #10
    Membre chevronné

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 389
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 389
    Points : 1 776
    Points
    1 776
    Par défaut
    Salut !

    Dans un premier temps... si on est dans un contexte d'ordonnancement de l'affichage, est-ce que la solution d'un Drag&Drop d'items d'une Listebox à une autre ne serait pas plus économique, à la place de N CheckBox ?
    On aurait donc :
    ListBox1 pour l'ensemble des propositions (liste des noms des champs)
    ListBox2 pour la liste des propositions retenues par l'utilisateur (ce que l'on va afficher dans l'ordre donné par la liste).
    C'est une première suggestion !
    Indication précieuse : la propriété Items du type TStrings (pour TListBox) sait gérer deux listes : Strings (ce que l'on voit) et Objects (ce que l'on peut y associer) !

    En ce qui concerne le fichier lui-même.
    Si on doit extraire des données... autant le faire qu'une seule fois en les organisant de manière à les retrouver immédiatement !
    A t-on la possibilité ici de convertir ce fichier sous la forme d'un ensemble de StringList (une par champ) chacune d'elle étant accrochée à son item dans la listbox des propositions !
    L'ordonnancement de l'affichage deviendrait alors un jeu d'enfant !

    A plus !

  11. #11
    Futur Membre du Club
    Inscrit en
    Janvier 2009
    Messages
    24
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 24
    Points : 9
    Points
    9
    Par défaut
    J'estime le nombre de type de donnée à plus de 350, donc si je décode tout pour les stocker dans des stringlist, sa me fera plus de 350 Stringlist avec un nombre d'item allant de 1 à 255. J'ai peur que ça pose problème au niveau de la mémoire et du temps de traitement, surtout sur des PC un peu ancien. C'est pour ça que je décode mes donnés à chaque fois que je veux les afficher

    J'aurai donc, avec ma méthode plus de 350 checkbox, que j'ai regroupé par catégorie dans des menus, et donc aussi plus de 350 colonnes potentielle (je pense limiter à 20 le nombre de colonnes affiché simultanément).

    voici à quoi ressemble mon appli:
    ici j'ai appuyé sur le bouton supply qui m'affiche le menu qui est au centre de l'écran et qui permet de sélectionner les données de la catégorie supply.




    Indication précieuse : la propriété Items du type TStrings (pour TListBox) sait gérer deux listes : Strings (ce que l'on voit) et Objects (ce que l'on peut y associer) !
    Je ne connais pas du tout, mais ça me parait intéressant. Où fait-on cette association?

    Sinon, je revient sur ma question précédente : Est-il possible de faire un tableau de pointeur vers des checkbox (ou autre composant)?

    Merci de ton aide.

  12. #12
    Membre chevronné

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 389
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 389
    Points : 1 776
    Points
    1 776
    Par défaut
    Salut !

    J'ai eu comme un vertige avec tes 350 checkbox !!!
    On va faire avec !

    Quel est le schéma de formatage des données pour une fiche ?

    Est-ce qu'elle est récupérée sous forme d'un bloc d'octets ?

    Parce qu'il existe d'autres solutions... qui dépendent précisément de ce formatage.

    A plus !

  13. #13
    Futur Membre du Club
    Inscrit en
    Janvier 2009
    Messages
    24
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 24
    Points : 9
    Points
    9
    Par défaut
    Voici la structure de mon fichier:


    Les paramètres de configuration sont codé différemment. Parfois une donnée (paramètre) est codé sur un octets, parfois plusieurs donné sont codé sur un octets (quelque bits par données) et quelque fois des donnés sont codé sur quelque bits dans plusieurs octets différents. c'est un beau bazar.
    Heureusement on m'a fournit un document (papier) qui me donne les offsets en mémoire et le codage des différentes donnée.

    Donc je charge mon fichier en mémoire avec : HandleFichierR = FileOpen(NomFichierCp, fmOpenRead);
    Je me place à l'offset (à partir du début du fichier) où je veux lire avec : FileSeek(HandleFichierR, offset, 0);
    je lis avec : FileRead(HandleFichierR, pszBuffer, nbOctets);

  14. #14
    Membre chevronné

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 389
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 389
    Points : 1 776
    Points
    1 776
    Par défaut
    Salut !

    Je rédige à la volée donc ...

    Pour mettre en liste l'ensemble des CheckBox, tu peux utiliser une TList.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    //déclaration en global
    TList *Liste;
    Dans le constructeur de la form principale:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Liste = new TList;
    for(int j = 0; j < ComponentCount; j++)
        {
        if(Components[j]->ClassNameIs("TCheckBox")) Liste->Add(Components[j]);
        }
    Et dans la OnClose de cette form principale :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Liste->Clear();
    delete Liste;
    Si d'autres form utilisent d'autres CheckBox il faudra leur rajouter :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    extern TList *Liste;
    Et dans leur constructeur se contenter de :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    for(int j = 0; j < ComponentCount; j++)
        {
        if(Components[j]->ClassNameIs("TCheckBox")) Liste->Add(Components[j]);
        }
    A partir de là, Liste pointera sur l'ensemble des CheckBox.

    Bien entendu entre temps, tu auras sans doute affecté une valeur d'index au Tag de chaque CheckBox.
    Ce qui permettra de récupérer ainsi la fonction qui leur est associée, depuis une table.
    Ca reste vrai aussi pour récupérer d'éventuels paramètres.

    La récupération des CheckBox cochés devrait se faire ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Liste *Champs = new TList;
    for(int j = 0; j < Liste->Count; j++)
        {
        if( ((TCheckBox*)Liste->Items[j])->Checked ) Champs->Add(Liste->Items[j] );
        }
    L'astuce consiste donc à faire :

    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
     
    StringGrid1->ColCount = Champs->Count;
    // On déroule l'affichage de toutes les fiches
    for(int row = 0; row < StringGrid1->RowCount; row++)
        {
        // Lecture d'une fiche dans le buffer
        // ...
        // On déroule l'affichage des champs répertoriés dans la liste Champs
        for(int col = 0; col < Champs->Count; col++)
            {
            int p = ((TCheckBox*)Champs->Items[col])->Tag;
            // je me contente ici de passer l'index comme paramètre
            StringGrid1->Cells[col][row] = Fonctions[ p ]( p );
            }
        }
    Ca suppose donc un tableau de pointeurs vers fonction qu'il est toujours possible d'initialiser d'entrée de jeu si les fonctions sont déclarées en amont :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    AnsiString Fct0(...parmètres ...);
    AnsiString Fct1(...parmètres ...);
    AnsiString Fct2(...parmètres ...);
    //..
     
    AnsiString (*F[MaxChamps])(...parametres...) = {Fct0, Fct1, Fct2...};
    Et peut-être des tableaux supplémentaires :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    int Parametre1[MaxChamps]={...};
    Je pense que tu as tout en main !
    A toi de jongler pour apporter tes fonctionnalités de filtrage !

    Bon courage !

    A plus !

  15. #15
    Futur Membre du Club
    Inscrit en
    Janvier 2009
    Messages
    24
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 24
    Points : 9
    Points
    9
    Par défaut
    Pwoua, merci beaucoup! Je comprend pourquoi il est écrit "Membre Expert" sous ton pseudo.

    Par contre je testerais tout ça dans 3 semaines, car je suis un Newbie de stagiaire et là je vais avoir deux semaines de cours, évidement je ne traine pas mon code avec moi.^^

    Je pense que ça va bien m'aider en tout cas. Je vois un ou deux trucs auxquels j'avais pensé cet aprèm (En cherchant sur ce super forum biensure).

    Je repasserai donc dans 3 semaines.

    A plus.

  16. #16
    Membre chevronné

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 389
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 389
    Points : 1 776
    Points
    1 776
    Par défaut
    Salut !

    Il existe une autre solution "un peu plus sympa" en lieu et place que celle des checkBox.
    C'est l'idée que j'avais proposée...

    Il s'agit de remplacer ces checkbox par de simples labels (on garde l'idée du Tag)
    On positionne leur propriété DragMode sur dmAutomatic.

    On va faire en sorte que la StringGrid réagisse sur un DragOver d'un de nos Labels :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void __fastcall TForm1::StringGrid1DragOver(TObject *Sender,
          TObject *Source, int X, int Y, TDragState State, bool &Accept)
    {
    Accept = Source->ClassNameIs("TLabel");
    }
    Et puis on lui donne de quoi prendre en compte le label qui est déposé sur une des cellules de la ligne des titres.
    La colonne prend comme titre le caption du label et l'affichage de la colonne se fait tout de suite après (sur le même principe qu'avec les CheckBox)

    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
     
    void __fastcall TForm1::StringGrid1DragDrop(TObject *Sender,
          TObject *Source, int X, int Y)
    {
    TLabel *Champ;
    if(Source->ClassNameIs("TLabel"))
        {
        Champ = (TLabel*)Source;
        int p = Champ->Tag;
        int col;
        int row;
        // On récupère les indices de la cellule sous X,Y
        StringGrid1->MouseToCell(X,Y, col, row);
        if((row == 0) && (col > 0))
            {
            // on évite tout doublon
            if(StringGrid1->Rows[0]->IndexOf(Champ->Caption) == -1)
                {
                // On prend en compte le nouveau titre
                StringGrid1->Cells[col][0] = Champ->Caption;
     
                //On déroule l'affichage pour la colonne
                for(row=1; ...)
                    {
                    //...
                    StringGrid1->Cells[col][row] = Fonctions[ p ]( p );
                    }
                }
            }
        }
    }
    C'est plus simple puisqu'on n'a rien à gérer de plus !
    L'utilisateur a toute liberté pour filtrer comme bon lui semble !

    A plus !

  17. #17
    Futur Membre du Club
    Inscrit en
    Janvier 2009
    Messages
    24
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 24
    Points : 9
    Points
    9
    Par défaut
    J'ai fait un mix de tes solutions pour utiliser les CheckBox.

    J'ai déclaré un tableau de pointeur vers fonction:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    AnsiString __fastcall(__closure *Fonctions[1]) ( int ) ;
    Fonctions[0]=Fonctions1;
    Fonctions[1]=Fonctions2;
    J'ai créé cette fonction, en m'inspirant de tes exemples, que j'appelle lors d'un clic sur les CheckBox:

    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
    void __fastcall TForm1::CheckBox1Click(TObject *Sender)
    {
     
    class TPublicStringGrid: public TCustomGrid
    {
        public:
            using TCustomGrid::DeleteRow;
            using TCustomGrid::DeleteColumn;
    };
     
     
    TCheckBox *Champ;
    if(Sender->ClassNameIs("TCheckBox"))
        {
        Champ = (TCheckBox*)Sender;
        int FTag = Champ->Tag;
        int col;
        int row=0;
     
     
        if(Champ->Checked==true)
            {
            // on évite tout doublon
            if(StringGrid1->Rows[0]->IndexOf(Champ->Caption) == -1)
                {
                 StringGrid1->ColCount++;
                // On prend en compte le nouveau titre
                col=StringGrid1->ColCount-1;
                StringGrid1->Cells[col][0] = Champ->Caption;
     
                //On déroule l'affichage pour la colonne
                for(row=1; row<10; row++)
                    {
                    //...
                    StringGrid1->Cells[col][row] = Fonctions[ FTag ]( row );
                    }
                }
            }
        else //suppression de la colonne si la checkbox est décoché.
            {
            if(StringGrid1->Rows[0]->IndexOf(Champ->Caption) !=-1)
            {
             ((TPublicStringGrid*)StringGrid1)->DeleteColumn(StringGrid1->Rows[0]->IndexOf(Champ->Caption));
            }
          }
        }
     
    }
    Et voila, le programme gère tout, tout seul! (enfin presque...)
    Pour l'instant ça marche pas trop mal, je repasserai si j'ai d'autres problèmes.

    En tout cas, merci beaucoup.

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 20/08/2013, 14h38
  2. comment passer un ArrayList comme paramètre d'une méthode
    Par itmak dans le forum Collection et Stream
    Réponses: 7
    Dernier message: 22/11/2008, 10h31
  3. Réponses: 3
    Dernier message: 20/08/2008, 14h22
  4. Réponses: 0
    Dernier message: 14/11/2007, 21h02
  5. [Débutant] Comment passer un fichier en paramètre d'une fonction?
    Par Rires et Chansons dans le forum MATLAB
    Réponses: 4
    Dernier message: 23/10/2007, 21h12

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