FAQ VC++ et MFCConsultez toutes les FAQ

Nombre d'auteurs : 20, nombre de questions : 546, dernière mise à jour : 5 avril 2013  Ajouter une question

 

Cette faq a été réalisée pour répondre aux questions les plus fréquement posées sur le forum Développement Visual C++

Je tiens à souligner que cette faq ne garantit en aucun cas que les informations qu'elle contient sont correctes ; Les auteurs font le maximum, mais l'erreur est humaine. Si vous trouvez une erreur, ou si vous souhaitez devenir redacteur, lisez ceci.

Sur ce, je vous souhaite une bonne lecture. Farscape


SommaireContrôlesCPropertySheet (4)
précédent sommaire suivant
 

Par défaut ce bouton est inactif.
Pour l'activer, il faut initialiser l'indicateur de modification de la page via SetModified(TRUE) lorsque l'utilisateur a modifié une page.
On surcharge pour cela la fonction OnCommand de chaque CPropertyPage.

Code c++ : Sélectionner tout
1
2
3
4
5
BOOL CMyPropertyPage::OnCommand(WPARAM wParam, LPARAM lParam)  
{ 
SetModified(TRUE); 
return CPropertyPage::OnCommand(wParam, lParam); 
}
Ensuite on surcharge la fonction OnApply de la classe dérivée de CPropertyPage dans laquelle on a défini la fonction CWndReceived (voir Q/R précédente).
Il n'est pas besoin de redéfinir OnApply pour les autres pages.
Deux possibilités :
soit on traite l'action engendrée par le clic sur le bouton "Appliquer" (et "OK") dans OnApply (ce qui suppose de caster le CWnd* en la classe dérivée de CWnd qui gère la propertysheet et d'inclure le .h correspondant), solution moche
soit on utilise le message personnalisé que peut envoyer la propertypage à la classe dérivée de CWnd réceptrice.

On va utiliser la 2ème solution et laisser le soin à la classe dérivée de CWnd de gérer ce qui doit être fait après que l'utilisateur a appuyé sur "Appliquer" ou "OK".

On définit le message personnalisé dans le source de la propertypage

Code c++ : Sélectionner tout
1
2
// par exemple 
#define WM_USERAPPLY WM_USER+5
et on surcharge OnApply pour cette même propertypage

Code c++ : Sélectionner tout
1
2
3
4
5
BOOL CMyPropertyPage::OnApply()  
{ 
m_pReceiver->SendMessage(WM_USERAPPLY); 
return CPropertyPage::OnApply(); 
}
On intercepte ensuite le message personnalisé WM_USERAPPLY dans la classe dérivée de CWnd qui gère la propertysheet (par exemple une view)

Code c++ : Sélectionner tout
1
2
3
4
5
6
BEGIN_MESSAGE_MAP(CMyView, CView) 
//{{AFX_MSG_MAP(CMyView) 
ON_COMMAND(ID_MENU_MACHIN, OnMenuMachin) 
//}}AFX_MSG_MAP 
ON_MESSAGE(WM_USERAPPLY, OnUserApply) 
END_MESSAGE_MAP()
et on ajoute le gestionnaire OnUserApply correspondant

Code c++ : Sélectionner tout
1
2
3
4
5
6
protected: 
//{{AFX_MSG(CMyView) 
afx_msg void OnMenuMachin(); 
afx_msg LRESULT OnUserApply(WPARAM wParam, LPARAM lParam); 
//}}AFX_MSG 
DECLARE_MESSAGE_MAP()
Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
LRESULT CMyView::OnUserApply(WPARAM wParam, LPARAM lParam) 
{ 
   TRACE("CMyView::OnUserApply -- wParam = %x\n", wParam); 
  
   // on utilise les valeurs des membres des pages de m_pPS 
   // pour faire quelquechose :-) 
   ... 
  
   return 0; 
}
et c'est gagné!

Mis à jour le 27 novembre 2005 bigboomshakala

Une feuille de propriétés est une boîte de dialogue à onglets (pages de propriétés) possédant 3 boutons "OK", "Annuler" et "Appliquer".

Pour construire une feuille de propriétés il faut :

utiliser l'éditeur de ressources pour créer un modèle de dialogue par onglet. Le titre des boîtes de dialogue (Caption) sera le titre des onglets.
générer une classe dérivant de CPropertyPage pour chaque modèle de dialogue, ajouter des membres pour les contrôles. Si on compte implémenter l'action du bouton "Appliquer" alors ajouter la fonction CWndReceiver et un membre CWnd* dans l'une des classes pages.

Code c++ : Sélectionner tout
1
2
3
4
5
private: 
   CWnd* m_pReceiver; 
  
public: 
   void CWndReceiver(CWnd* pReceiver) { m_pReceiver = pReceiver; }
générer une classe dérivant de CPropertySheet, lui ajouter une variable membre pour chaque page et appeler AddPage dans le constructeur pour chaque page.

Code c++ : Sélectionner tout
1
2
3
public: 
   CMyPropertyPage1 m_page1; 
   CMyPropertyPage2 m_page2;
Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
CMyPropertySheet::CMyPropertySheet(LPCTSTR pszCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0) 
{ 
   AddPage(&m_page1); 
   AddPage(&m_page2); 
  
   // si CWndReceiver a été implémenté 
   // attention : pParentWnd ne devra jamais être NULL 
   // le mieux est d'enlever la valeur NULL par défaut 
   m_page1.CWndReceiver(pParentWnd); 
}
dans l'application, construire une instance de la classe dérivée de CPropertySheet et appeler DoModal (préférer un pointeur afin de pouvoir passer l'adresse de l'objet dérivé de CWnd appelant).
Par exemple dans une classe vue CMyView

Code c++ : Sélectionner tout
1
2
private: 
   CMyPropertySheet * m_pPS;
Code c++ : Sélectionner tout
1
2
3
4
CMyView::CMyView(...):CView(...) 
{ 
   m_pPS = new CMyPropertySheet("Titre",this); 
}
Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// événement de clic sur le menu ouvrant la propertysheet 
CMyView::OnMenuMachin() 
{ 
   ... 
  
   // On peut modifier le titre 
   m_pPS ->SetTitle("Eventuellement, modification du titre"); 
  
   // On peut donner des valeurs aux membres des pages 
   // Si on ne le fait pas avant le DoModal, les valeurs seront 
   // celles par défaut ou celles données dans le constructeur 
   // de chaque page 
   m_pPS ->m_page1.m_attr1 = ... ; 
   m_pPS ->m_page1.m_attr2 = ... ; 
   m_pPS ->m_page2.m_attr1 = ... ; 
   m_pPS ->m_page2.m_attr2 = ... ; 
  
   // On fait apparaître la propertysheet 
   m_pPS->DoModal(); 
}
Code c++ : Sélectionner tout
1
2
3
4
CMyView::~CMyView() 
{ 
   delete m_pPS; 
}
Eventuellement, implémenter le comportement du bouton "Appliquer" (inactif par défaut). Le clic sur "OK" quant à lui est déjà géré et actualise toutes les variables membres des pages.

Mis à jour le 27 novembre 2005 bigboomshakala

Exemple:

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  
BOOL CMyPropSheet::OnInitDialog () 
{ 
    BOOL bResult = CPropertySheet::OnInitDialog(); 
  
   int ids [] = {IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP }; 
  
  CWnd *pWnd; 
  for(int i=0;i<sizeof(ids)/sizeof(int);i++) 
  { 
       pWnd = GetDlgItem( ids[i] ); 
       if(pWnd) 
       { 
        pWnd->EnableWindow(FALSE); 
    pWnd->ShowWindow( SW_HIDE ); 
   } 
  } 
//.................
pour désactiver le bouton Appliquer au démarrage on interviendra directement sur le style du contrôle:

Code c++ : Sélectionner tout
1
2
3
4
5
6
  
//CPropertySheet dlgPropertySheet("Simple"); 
  
dlgPropertySheet.m_psh.dwFlags |= PSH_NOAPPLYNOW; 
//..... 
dlgPropertySheet.DoModal();

Mis à jour le 20 mai 2006 farscape

Le lancement d'une boîte d'une CPropertySheetne permet pas de spécifier l'emplacement de celle-ci à l'écran.
La solution consistera à surcharger la fonction DoModal pour positionner notre fenêtre à l'emplacement voulu.
Exemple sur une classe dérivée de CPropertySheet:

Code c++ : Sélectionner tout
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  
#include <afxpriv.h> 
#include <AFXIMPL.H> // attention ce header est definit dans les sources des MFC ,on peut rajouter le chemin des src MFC dans la recherche des includes... 
  
int CMyPropertySheet::DoModal() 
{ 
   ASSERT_VALID(this); 
    ASSERT(m_hWnd == NULL); 
  
    // register common controls 
    VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTLS_REG)); 
    AfxDeferRegisterClass(AFX_WNDCOMMCTLSNEW_REG); 
  
    // finish building PROPSHEETHEADER structure 
    BuildPropPageArray(); 
  
    // allow OLE servers to disable themselves 
    CWinApp* pApp = AfxGetApp(); 
    if (pApp != NULL) 
        pApp->EnableModeless(FALSE); 
  
    // find parent HWND 
    HWND hWndTop; 
    HWND hWndParent = CWnd::GetSafeOwner_(m_pParentWnd->GetSafeHwnd(), &hWndTop); 
    AFX_OLDPROPSHEETHEADER* psh = GetPropSheetHeader(); 
    psh->hwndParent = hWndParent; 
    BOOL bEnableParent = FALSE; 
    if (hWndParent != NULL && ::IsWindowEnabled(hWndParent)) 
    { 
        ::EnableWindow(hWndParent, FALSE); 
        bEnableParent = TRUE; 
    } 
    HWND hWndCapture = ::GetCapture(); 
    if (hWndCapture != NULL) 
        ::SendMessage(hWndCapture, WM_CANCELMODE, 0, 0); 
  
    // setup for modal loop and creation 
    m_nModalResult = 0; 
    m_nFlags |= WF_CONTINUEMODAL; 
  
    // hook for creation of window 
    AfxHookWindowCreate(this); 
    psh->dwFlags |= PSH_MODELESS; 
    m_nFlags |= WF_CONTINUEMODAL; 
    HWND hWnd = (HWND)::PropertySheet((PROPSHEETHEADER*)psh); 
  
    if(m_nx || m_ny) // ma modification, trés modeste ... 
        ::SetWindowPos(hWnd,NULL,m_nx,m_ny,0,0,SWP_NOSIZE); 
  
#ifdef _DEBUG 
    DWORD dwError = ::GetLastError(); 
#endif 
    psh->dwFlags &= ~PSH_MODELESS; 
    AfxUnhookWindowCreate(); 
  
    // handle error 
    if (hWnd == NULL || hWnd == (HWND)-1) 
    { 
        TRACE1("PropertySheet() failed: GetLastError returned %d\n", dwError); 
        m_nFlags &= ~WF_CONTINUEMODAL; 
    } 
  
    int nResult = m_nModalResult; 
    if (ContinueModal()) 
    { 
        // enter modal loop 
        DWORD dwFlags = MLF_SHOWONIDLE; 
        if (GetStyle() & DS_NOIDLEMSG) 
            dwFlags |= MLF_NOIDLEMSG; 
        nResult = RunModalLoop(dwFlags); 
    } 
  
    // hide the window before enabling parent window, etc. 
    if (m_hWnd != NULL) 
    { 
        SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW| 
            SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER); 
    } 
    if (bEnableParent) 
        ::EnableWindow(hWndParent, TRUE); 
    if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd) 
        ::SetActiveWindow(hWndParent); 
  
    // cleanup 
    DestroyWindow(); 
  
    // allow OLE servers to enable themselves 
    if (pApp != NULL) 
        pApp->EnableModeless(TRUE); 
    if (hWndTop != NULL) 
        ::EnableWindow(hWndTop, TRUE); 
  
    return nResult; 
}

l'include de la classe :

Code c++ : Sélectionner tout
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
  
///////////////////////////////////////////////////////////////////////////// 
// CMyPropertySheet 
  
class CMyPropertySheet : public CPropertySheet 
{ 
    DECLARE_DYNAMIC(CMyPropertySheet) 
  
// Construction 
public: 
    CMyPropertySheet(CWnd* pWndParent = NULL); 
    virtual int    DoModal(); 
    void SetCoord(int x,int y){m_nx=x;m_ny=y;} 
// Attributes 
public: 
    CMyPropertyPage1 m_Page1; 
    CMyPropertyPage2 m_Page2; 
    CMyPropertyPage3 m_Page3; 
  
// Operations 
public: 
int m_nx,m_ny; // Attention : Initialisé a 0 dans le constructeur .... 
  
// Overrides 
    // ClassWizard generated virtual function overrides 
    //{{AFX_VIRTUAL(CMyPropertySheet) 
    //}}AFX_VIRTUAL 
  
// Implementation 
public: 
    virtual ~CMyPropertySheet(); 
     virtual void PostNcDestroy(); 
  
// Generated message map functions 
protected: 
    //{{AFX_MSG(CMyPropertySheet) 
        // NOTE - the ClassWizard will add and remove member functions here. 
    //}}AFX_MSG 
    DECLARE_MESSAGE_MAP() 
};
Attention n'oubliez pas d'initialiser les variables m_nx et m_ny dans le constructeur...
Utilisation dans le cadre de mon exemple:

Code c++ : Sélectionner tout
1
2
3
4
  
CMyPropertySheet dlg; 
dlg.SetCoord(500,200); 
dlg.DoModal();

Mis à jour le 22 janvier 2007 farscape

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2017 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

 
Contacter le responsable de la rubrique C++