IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo
Sommaire > Contrôles > CPropertySheet
        Comment gérer le bouton 'Appliquer' d'une feuille de propriétés ?
        Comment créer une feuille de propriétés ?
        Comment désactiver les boutons d'un CPropertysheet ?
        Comment afficher une CPropertySheet à une coordonnée choisie ?



Comment gérer le bouton "Appliquer" d'une feuille de propriétés ?
Créé le 27/11/2005[haut]
auteur : Nourdine Falola
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.
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
// par exemple
#define WM_USERAPPLY WM_USER+5
et on surcharge OnApply pour cette même propertypage
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)
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
protected:
//{{AFX_MSG(CMyView)
afx_msg void OnMenuMachin();
afx_msg LRESULT OnUserApply(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
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é!


Comment créer une feuille de propriétés ?
Créé le 27/11/2005[haut]
auteur : Nourdine Falola
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.
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.
public:
   CMyPropertyPage1 m_page1;
   CMyPropertyPage2 m_page2;
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
private:
   CMyPropertySheet * m_pPS;
CMyView::CMyView(...):CView(...)
{
   m_pPS = new CMyPropertySheet("Titre",this);
}
// é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();
}
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.


Comment désactiver les boutons d'un CPropertysheet ?
Créé le 20/05/2006[haut]
auteur : Farscape
Exemple:

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:

//CPropertySheet dlgPropertySheet("Simple");

dlgPropertySheet.m_psh.dwFlags |= PSH_NOAPPLYNOW;
//.....
dlgPropertySheet.DoModal();

Comment afficher une CPropertySheet à une coordonnée choisie ?
Créé le 22/01/2007[haut]
auteur : Farscape
Le lancement d'une boîte d'une CPropertySheet ne 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:

#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 :

/////////////////////////////////////////////////////////////////////////////
// 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:

CMyPropertySheet dlg;
dlg.SetCoord(500,200);
dlg.DoModal();



Consultez les autres F.A.Q.


Valid XHTML 1.0 TransitionalValid CSS!

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 © 2004 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni 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.