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

Windows Discussion :

[c++]Mettre une procédure de fenetre dans une class


Sujet :

Windows

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    180
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 180
    Points : 90
    Points
    90
    Par défaut [c++]Mettre une procédure de fenetre dans une class
    Bonjour à tous,

    Je suis en train de créer une class TABLEAU dans laquelle se trouve une WNDCLASSEX appelée cTableau!
    La procédure de fenetre de cTableau doit absolument manipuler des éléments private de la class TABLEAU.

    Du coup, je dois obligatoirement mettre la WindowProc dans la class TABLEAU.

    J'écris donc, dans le fichier tableau.h

    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
    #ifndef TABLEAU_H_
    #define TABLEAU_H_
    
    #include <windows.h>
    
    
    
    typedef struct _CASE&#123;
    RECT coordonnees;
    char contenu&#91;250&#93;;
    
    &#125;CASE;
    
    class TABLEAU
    &#123;
          private&#58;
          CASE &#40;* cases&#41;&#91;2&#93;;
          HWND edit_temporaire;
          char buffer&#91;250&#93;;
          CASE *pCase;
          WNDCLASSEX cTableau;
          int nLignes,nColonnes;
    //Les méthodes associées
          LRESULT CALLBACK procedure&#40;HWND , UINT , WPARAM , LPARAM &#41;;
          public&#58;
          TABLEAU&#40;HINSTANCE hInstance,int nLignes, int nColonnes&#41;;
          &#125;;
    
    #endif
    Et, le constructeur de cette classe initialise les membres de la WNDCLASSEX cTableau.

    Je suis donc amené à écrire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    cTableau.lpfnWndProc=procedure;
    Le problème c'est que mon compilateur me renvoie l'erreur suivante sur cette ligne :

    argument of type 'LRESULT(TABLEAU:(HWND__*,UINT,WPARAM,LPARAM)'does not match 'LRESULT (*)(HWND__*,UINT,WPARAM,LPARAM)'
    Voilà! J'aimerais savoir d'où provient cette erreur et comment la contourner.

    Merci d'avance.

    Spartan03
    Pourquoi faire simple quand on peut faire compliqué!

  2. #2
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 751
    Points : 10 670
    Points
    10 670
    Billets dans le blog
    3
    Par défaut
    Il faut que ta procédure soit statique.

  3. #3
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    IL y avait un exemple dans les "COM tutorial samples" de MSDN: Tu déclares ta procédure en static, et lors du CreateWindow[Ex], tu passes le pointeur de ta classe en paramètre. Tu le récupères ainsi lors du WM_CREATE, et tu le stocke dans GWL_USERDATA avec un petit SetWindowLong() ou SetWindowLongPtr()...

    Ainsi, lorsque tu as besoin de manipuler les données de ton objet, tu récupères son adresse avec GetWindowLong() ou GetWindowLongPtr(), et tu travailles sur ce pointeur-là (normalement, puisque la fonction est membre de la classe, elle devrait avoir accès aux données privées)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  4. #4
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 751
    Points : 10 670
    Points
    10 670
    Billets dans le blog
    3

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    180
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 180
    Points : 90
    Points
    90
    Par défaut
    Si j'ai bien compris, il faudrait que je mette ma fonction membre en static pour que ça marche. Sauf que si une méthode est en static, elle n'accepte plus "this" donc en clair, je ne peux plus modifier d'éléments de ma classe qu'ils soient private ou public. Et c'est là que j'ai pas tout compris? Je vais néanmoins essayer de me débrouiller avec ce que vous m'avez donné en le relisant bien attentivement et (ré)essayer de comprendre.

    Merci à tous
    Pourquoi faire simple quand on peut faire compliqué!

  6. #6
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 751
    Points : 10 670
    Points
    10 670
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par Spartan03
    Si j'ai bien compris, il faudrait que je mette ma fonction membre en static pour que ça marche. Sauf que si une méthode est en static, elle n'accepte plus "this" donc en clair, je ne peux plus modifier d'éléments de ma classe qu'ils soient private ou public.
    C'est ça, et c'est pourquoi tu dois associer le pointeur this au HWND, afin de pouvoir récupérer une instance de ta classe à partir d'un HWND. Y'a plusieurs méthodes, tu as eu un rapide apperçu.

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    180
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 180
    Points : 90
    Points
    90
    Par défaut
    Désolé mais je ne suis pas très sur d'avoir compris. Pour que ça marche, il faut que ma classe soit en static mais reste-t-il encore un moyen de modifier des membres de cette dernière. Car je ne peux pas modifier les arguments d'une WindowProc. Là, j'avoue que je suis un peu perdu. L'autre alternative consisterai donc à ne pas mettre la procédure en static auquel cas il y'a une erreur à la ligne suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    cTableau.lpfnWndProc=procedure;
    Je vous donne également le fichier tableau.cpp si cela peut vous aider. (il est incomplet pour l'instant)

    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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    #include "tableau.h"
    
    TABLEAU&#58;&#58;TABLEAU&#40;HINSTANCE hInstance,int noLignes, int noColonnes&#41;
    &#123;
         //On crée et enregistre la WndClassEx cTableau
         cTableau.cbSize=sizeof&#40;WNDCLASSEX&#41;;
        cTableau.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
        cTableau.lpfnWndProc=procedure;
        cTableau.cbClsExtra=0;
        cTableau.cbWndExtra=0;
        cTableau.hInstance=hInstance;
        cTableau.hIcon=LoadIcon&#40;NULL, IDI_APPLICATION&#41;;
        cTableau.hCursor = LoadCursor &#40;NULL, IDC_IBEAM&#41;;
        cTableau.hbrBackground = &#40;HBRUSH&#41; CreateSolidBrush&#40;RGB&#40;200,200,200&#41;&#41;;
        cTableau.lpszMenuName = NULL;
        cTableau.lpszClassName = "TABLEAU";
        cTableau.hIconSm = 0;
        
        RegisterClassEx&#40;&cTableau&#41;;
         
         
         
         //On crée un TABLEAU au nombre de lignes/colonnes demandées
         cases = new CASE&#91;noLignes&#93;&#91;2&#93;;
         //On enregistre les valeurs du nombre de lignes et de colonnes
         nLignes = noLignes; nColonnes = noColonnes;
    &#125;
    
    LRESULT CALLBACK TABLEAU&#58;&#58;procedure&#40;HWND fenetre, UINT message, WPARAM wParam, LPARAM lParam&#41;
    &#123;
        switch&#40;message&#41;
        &#123;
            case WM_PAINT&#58;
                 //On récupère les dimensions de la zone client dans un RECT
                 RECT client;
                 GetClientRect&#40;fenetre,&client&#41;;
                 //-----------------------------------
                 
                 //On calcule les coordonnées des futurs cases
                 int a;
                 for&#40;a=0;a<=nLignes;a++&#41;
                 &#123;
                    //On calcule celles de la case de droite courante!
                    this.cases&#91;a&#93;&#91;1&#93;.coordonnees.left = client.left;
                    this.cases&#91;a&#93;&#91;1&#93;.coordonnees.top = a*20;
                    this.cases&#91;a&#93;&#91;1&#93;.coordonnees.right = client.right/2;
                    this.cases&#91;a&#93;&#91;1&#93;.coordonnees.bottom = &#40;a+1&#41;*20;
                    
                    //On calcule celles de la case de gauche courante
                 &#125;
                 
                 
            break;
            //----------------------------------------------------------------------
            case WM_DESTROY&#58;
                 PostQuitMessage&#40;0&#41;;
            break;
            //----------------------------------------------------------------------
            default&#58;
              return DefWindowProc&#40;fenetre,message,wParam,lParam&#41;;
        &#125;
    &#125;
    Merci d'avance de m'éclairer sur ce point la
    Pourquoi faire simple quand on peut faire compliqué!

  8. #8
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 751
    Points : 10 670
    Points
    10 670
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par Spartan03
    Désolé mais je ne suis pas très sur d'avoir compris. Pour que ça marche, il faut que ma classe soit en static mais reste-t-il encore un moyen de modifier des membres de cette dernière. Car je ne peux pas modifier les arguments d'une WindowProc. Là, j'avoue que je suis un peu perdu. L'autre alternative consisterai donc à ne pas mettre la procédure en static auquel cas il y'a une erreur à la ligne suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    cTableau.lpfnWndProc=procedure;
    sauf que ça n'est pas possible, car tu as un paramètre caché this en plus si elle est pas static. Windows ne peut pas gérer ce pointeur caché, car il est lié à ton programme C++. C'est donc à toi de le gérer, et de l'associer à ton HWND.
    L'idée, c'est d'avoir des fonctions SetPtr/GetPtr qui te permette d'associer une isntance de ta classe à un HWND:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void SetPtr&#40; HWND hWnd, TABLEAU *Ptr &#41;
    &#123;
        SetWindowLongPtr&#40; hWnd, GWL_USERDATA, reinterpret_cast<DWORD>&#40; Ptr &#41; &#41;; 
    &#125;
    
    TABLEAU* GetPtr&#40; HWND hWnd &#41;
    &#123;
        return reinterpret_cast<TABLEAU*>&#40;
            GetWindowLongPtr&#40; hWnd, GWL_USERDATA &#41; &#41;; 
    &#125;
    Tu utilises ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    case WM_NCCREATE&#58;
        SetPtr&#40; hWnd, new Tableau &#41;;
    
    case WM_PAINT&#58;
        TABLEAU *ptr = GetPtr&#40; hWnd &#41;;
        if &#40; ptr != 0 &#41;
        &#123;
            ptr->cases&#91;a&#93;&#91;1&#93;.coordonnees.left = ...
        &#125;
    
    case WM_NCDESTROY&#58;
        delete GetPtr&#40; hWnd &#41;;
    Dans cet exemple j'utilise GWL_USERDATA, mais en principe il ne faudrait pas acr c'est réservé à celui qui crée la fenêtre, il serait préférable d'utiliser des extra bytes dans ta classe.

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Mais dans les cas où tu ne peux régler les Window Bytes toi-même (Ex: boîte de dialogue), tu peux également utiliser les Window Properties, qui bien que lentes, sont une bonne solution de rechange (SetProp()/GetProp())
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    180
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 180
    Points : 90
    Points
    90
    Par défaut
    Ok, je vais essayer de me débrouiller, je ne pense pas que je vais utiliser les Windows Bytes car tout ce que je sais faire avec, c'est les allouer.

    Merci pour tout!
    Pourquoi faire simple quand on peut faire compliqué!

  11. #11
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 751
    Points : 10 670
    Points
    10 670
    Billets dans le blog
    3
    Par défaut
    Ca fonctionne pareil que GWL_USERDATA, qui est en quelque sorte un extra byte automatique. GetWindowLong( 0 ) te renvoie le premier "extra long"...
    Avec les props, faut pas oublier de libérer ensuite.

Discussions similaires

  1. [Débutant] Insérer un nouvel objet dans une relation 1 : n (avec une procédure stockée)
    Par Binenebi dans le forum Entity Framework
    Réponses: 9
    Dernier message: 01/05/2013, 14h08
  2. Réponses: 7
    Dernier message: 27/06/2011, 15h56
  3. Réponses: 1
    Dernier message: 26/12/2010, 21h20
  4. Réponses: 1
    Dernier message: 03/09/2009, 12h39
  5. Réponses: 4
    Dernier message: 28/08/2006, 13h04

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