IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo
Sommaire > Classes Fenêtres et FrameWork > Boite de Dialogue > CDialog
        Comment donner le focus à un contrôle à partir d'OnInitDialog ?
        Comment traiter l'acceptation d'une boîte de dialogue ?
        Comment intercepter les touches entrée et échappement dans une boîte de dialogue ?
        Comment gérer la sortie d'une boîte de dialogue ?
        Comment accéder aux contrôles d'une boîte de dialogue à partir d'une autre boîte de dialogue ?
        Comment charger les contrôles d'une CDialog avant DoModal() ?
        Comment récupérer la fenêtre parent dans une boîte de dialogue ?
        Comment mettre des fenêtres de contrôles dynamiquement dans une boîte de dialogue ?
        Comment démarrer une boîte de dialogue en mode caché ?
        Comment lancer un traitement au démarrage d'une CDialog ?
        Comment rajouter un bouton agrandir et réduire sur une CDialog ?
        Comment faire une application boîte de dialogue sans bouton dans la barre des tâches Windows ?
        Comment rajouter un menu à une boîte de dialogue ?
        Pourquoi les notifications ON_UPDATE_COMMAND_UI ne fonctionnent pas dans une CDialog ?
        Comment rendre transparente une boîte de dialogue ?
        Comment mettre une image de fond dans une boîte de dialogue ?
        Comment faire pour qu'un projet boîte de dialogue soit toujours en avant plan ?
        Comment imprimer une boite de dialogue ?
        Comment créer une boîte de dialogue non modale ?
        Comment libérer la mémoire sur une fenêtre dynamique ?
        Comment est calculée l'unité de mesure d'une boîte de dialogue ?
        Comment afficher une CDialog depuis une DLL?
        Quand appeler la macro AFX_MANAGE_STATE(AfxGetStaticModuleState( )) ?
        Comment créer une boîte de dialogue dynamiquement sans ressources ?
        Comment copier une boîte de dialogue d'un projet à un autre ?
        Comment partager des données entre une CFormView et une CDialog ?
        Comment afficher une boîte de dialogue à des coordonnées choisies ?
        Comment mettre en place un raccourci clavier dans une boîte de dialogue ?
        Comment implémenter le tab stop entre deux boîtes de dialogue imbriquées ?
        Comment savoir si une boîte de dialogue non modale est active ?
        Comment donner le focus à un contrôle dans OnInitDialog ?



Comment donner le focus à un contrôle à partir d'OnInitDialog ?
Créé le 20/05/2006[haut]
auteur : Farscape
Par défaut la fonction OnInitDialog renvoie TRUE (valeur générée par visual) .
Ce qui sera interprété comme : donner le focus au premier contrôle suivant l'ordre de tabulation.
Si on souhaite donner le focus à un autre contrôle à partir de cette fonction il faudra retourner FALSE et utiliser la fonction SetFocus pour spécifier le contrôle de votre choix.


Comment traiter l'acceptation d'une boîte de dialogue ?
auteur : Farscape
Lorsque l'utilisateur utilisera la touche entrée ou le bouton OK dans une boîte de dialogue celle-ci se fermera automatiquement.
Pour placer un traitement sur l'acception il suffit de générer la méthode OnOk sur le bouton IDOK de la boîte de dialogue avec l'aide de « ClassWizard ».
Classiquement si on veut récupérer les valeurs pour qu'elles soient accessibles après l'appel de la fonction DoModal() , on exécutera la fonction UpdateData(TRUE) pour mettre à jour l'ensemble des variables , et on procédera éventuellement à des traitements supplémentaires .
Par exemple la récupération de la sélection en cours dans une CListBox sachant qu'après c'est trop tard?

void CMyDlg::OnOK() 
{ 
     m_nIndiceSel = m_ListBox.GetCurSel(); 
     if(m_nIndiceSel!=-1) 
     m_ListBox.GetText( m_nIndiceSel,m_strSel ); 
     CDialog::OnOK(); 
} 
void CMyView::OnShowDialog() 
{ 
   CMyDlg dlg ; 
   if (dlg.DoModal()==IDOK) 
   { 
      CString str ; 
      str.Format("%d:",dlg.m_nIndiceSel) ; 
      AfxMessageBox(str+dlg.m_strSel) ; 
   } 
}

Comment intercepter les touches entrée et échappement dans une boîte de dialogue ?
auteur : Farscape
En surchargeant la méthode OnCommand de la classe CWnd:

CWnd::OnCommand
virtual BOOL OnCommand(WPARAM wParam,LPARAM lParam ); 

BOOL CAboutDlg::OnCommand(WPARAM wParam, LPARAM lParam) 
{
    // TODO: Add your specialized code here and/or call the base class
    CWnd *pWnd = GetFocus();
    switch(wParam)
    {
      case IDOK: if(pWnd!=GetDlgItem(IDOK))
                 {
                      return FALSE;
                 }
                 break;

      case IDCANCEL:if(pWnd!=GetDlgItem(IDCANCEL))
                    {
                        return FALSE;
                    }
                    break;
    }
    return CDialog::OnCommand(wParam, lParam);
}
Le code ci-dessus permet d'interdire la fermeture de la fenêtre par la touche entrée si le contrôle possédant le « focus » n'est pas le bouton IDOK.
Même chose avec la touche Echappement , la fenêtre ne pourra pas se fermer si le bouton possédant le « focus » n'est pas le bouton IDCANCEL.
Une petite précision : lors de la femeture de la fenêtre par la croix le message IDCANCEL sera généré .
Ce qui ne sera pas le cas si pour récupérer les messages claviers on était passé par la fonction PreTranslateMessage de la classe Cwnd :

CWnd::PreTranslateMessage
virtual BOOL PreTranslateMessage( MSG* pMsg ); 

BOOL CAboutDlg::PreTranslateMessage(MSG* pMsg) 
{
  if(pMsg->message == WM_KEYDOWN)
  {
    if(pMsg->wParam == VK_ESCAPE)  return TRUE;
    if(pMsg->wParam == VK_RETURN)  return TRUE;
  }
  return CDialog::PreTranslateMessage(pMsg);
}
Dans le code ci-dessus on interceptera uniquement les messages en provenance du clavier :


Comment gérer la sortie d'une boîte de dialogue ?
Créé le 20/05/2006[haut]
auteur : Farscape
Les boîtes de dialogues disposent de deux événements boutons pour se fermer :
Le bouton OK associé à l'identifiant IDOK et le bouton Abandon associé à l'identifiant IDCANCEL.
A ces deux boutons sont associées respectivement les fonctions virtuelles de la classe CDialog :

virtual void OnOK();
virtual void OnCancel();
À la sortie de la boîte de dialogue DoModal renverra donc soit IDOK ou IDCANCEL.
Dans le cas où l'on souhaite avoir une autre valeur que celles prédéfinies on procédera comme suit.
Il suffira d'appeler la fonction EndDialog avec le numéro d'événement souhaité, exemple :
Si on doit fermer la boîte de dialogue sur le clic d'un autre bouton, il suffira de générer l'événement BN_CLICKED sur le bouton, et d'appeler la fonction EndDialog avec son identifiant.


Comment accéder aux contrôles d'une boîte de dialogue à partir d'une autre boîte de dialogue ?
auteur : Farscape
Le cas typique est de récupérer des informations de la deuxième boîte de dialogue pour renseigner la boîte de dialogue parent qui l'a créée.
L'accès aux contrôles d'une boîte de dialogue n'est possible que si celle-ci est active,c'est-à-dire tant que la fonction DoModal() n'a pas renvoyé le code de retour IDOK ou IDCANCEL.
Après DoModal() la boîte de dialogue n'est plus valide graphiquement donc toute tentative d'accès aux contrôles déclenchera une assertion d'erreur.
L'exemple ci-dessous illustre le sujet :
Une première boîte est lancée CDlg1 sur un click bouton on exécute la boîte de Dialogue CDlg2 .
Celle-ci aura comme parent Window l'objet de la classe CDlg1 .
Sur le OnOk de Cdlg2 on récupère l'accès à l'objet parent ce qui permet un échange de données avant que l'objet (CDlg2) ne soit plus valide graphiquement.


class CDlg1: public CDialog 
{
public:
CDlg1(CWnd* pParent = NULL);// standard constructor
        // Generated message map functions
//{{AFX_MSG(CDlg1)
virtual BOOL OnInitDialog();
afx_msg void OnButton1();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

class CDlg2: public CDialog 
{
public:
    CDlg2(CWnd* pParent = NULL);// standard constructor
// Generated message map functions
//{{AFX_MSG(CDlg2)
    virtual BOOL OnInitDialog();
    virtual void OnOK();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
};
// appel dlg1
CDlg1 dlg;
dlg.DoModal();

void CDlg1::OnButton1() 
{
    // TODO: Add your control notification handler code here
    CDlg2 dlg(this); // fournit comme parent CDlg1 par exemple 
                            // ou alors affectation à une variable interne.
                            // par un accesseur etc...
    dlg.DoModal(); 
}

void CDlg2::OnOK() 
{
    // TODO: Add extra validation here
    CDlg1 *pDlg=( CDlg1 *)GetParent();
    // Maintenant j'ai accès à la boite de dialogue CDlg1.

   CDialog::OnOK();
}

Comment charger les contrôles d'une CDialog avant DoModal() ?
auteur : Farscape
Rappels : Tant que la boîte de dialogue modale n'est pas initialisée graphiquement aucune mise à jour des contrôles n'est possible.
La boîte de dialogue modale est valide à partir de l'exécution de DoModal().
La première fonction disponible pour l'initialisation des contrôles : OnInitDialog
Les contrôles sont valides à partir du premier UpdateData voir post :Comment mettre à jour les contrôles depuis leurs variables et vice-versa ?

Plusieurs cas sont à étudier :
Les contrôles CEdit ou CStatic:
Avec l'aide de ClassWizard onglet member variables :
Attacher aux contrôles une variable de type CString ,int etc?

A l'appel de la boîte il suffit d'affecter les valeurs aux variables comme ci-dessus.

void CTestDlgDlg::OnButton1() 
{
// TODO: Add your control notification handler code here
        CDialog1 dlg;
        dlg.m_strEdit1="coucou" ;
        dlg.DoModal();
}
Dans la fonction OnInitDialog il restera à faire un UpdateData(FALSE) comme dans l'exemple ci-dessus :

BOOL CDialog1::OnInitDialog() 
{
CDialog::OnInitDialog();

// TODO: Add extra initialization here
UpdateData(FALSE); // mise à jour des contrôles
return TRUE;  // return TRUE unless you set the focus to a control
              // EXCEPTION: OCX Property Pages should return FALSE
}
Les Listbox et CCombox et autres contrôles gérant des listes : On ne peut pas affecter un tableau d'éléments aux contrôles, il faudra stocker les différentes valeurs dans un tableau dynamique de type CStringArray ,CArray ou vector et procéder au chargement des contrôles dans la fonction OnInitDialog.
Néanmoins je propose une solution pour les CListbox et CComboBox permettant d'écrire ceci :

CDialog1 Dlg;
Dlg.m_Listbox.AddString("essai");
Dlg.m_Listbox.AddString("essai1");
Dlg.DoModal();
La solution passe la définition d'une classe dérivée de CListBox et de la redéfinition de la fonction AddString :
Attention je précise que cette fonction n'est pas virtuelle dans la classe CListBox.

class CMyListBox : public CListBox
{
// Construction
public:
CMyListBox();

// Attributes
public:

int  AddString( LPCTSTR lpszItem );

// Operations
public:
CStringArray m_strArray;

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyListBox)
public:
protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL

// Implementation
public:
virtual ~CMyListBox();

// Generated message map functions
protected:
//{{AFX_MSG(CMyListBox)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

int CMyListBox::AddString(LPCTSTR lpszItem)
{
    // si la listbox est valide appel de la fonction d'origine. 
    if(m_hWnd!=NULL) return CListBox::AddString(lpszItem);
    m_strArray.Add(lpszItem);
    return LB_ERR;
}
void CMyListBox::PreSubclassWindow() 
{
// TODO: Add your specialized code here and/or call the base class
CListBox::PreSubclassWindow();    
    for(int i=0;i<m_strArray.GetSize();i++) AddString(m_strArray[i]);
}
Note:L'insertion du tableau dans le contrôle se fait dans la fonction PreSubclassWindow().


Comment récupérer la fenêtre parent dans une boîte de dialogue ?
Créé le 27/11/2005[haut]
auteur : Farscape
Lorsque l'on construit un objet boîte de dialogue le constructeur permet de spécifier la fenêtre parent de la dialogue

void CMyFormView::OnButtonMachin() // c'est un exemple bien sur ... 
{ 
 CMyDialog Dlg(this)

Dlg.DoModal(); 
}
Ensuite dans la dialogue il suffira d'appeler la fonction GetParent() pour récupérer notre parent :

BOOL CMyDialog::OnInitDialog() 
{ 
   CDialog::OnInitDialog(); 
   CMyFormView *pView=static_cast< CMyFormView *>(GetParent()); 
//?????
Néanmoins il y a un cas où ce code ne fonctionne pas : l'appel d'une boîte de dialogue à partir d'un panneau d'un TabControl .

Le pointeur retourné ne sera pas l'onglet mais la MainFrame .
On pourra contourner ce problème comme suit :

BOOL CMyDialog::OnInitDialog() 
{ 
   CDialog::OnInitDialog(); 
   CMyFormView *pView=static_cast< CMyFormView *>(m_pParentWnd); 
//?????
m_pParentWnd est une donnée membre protected de la classe CDialog ,elle est affectée par la valeur passée en argument dans le constructeur .


Comment mettre des fenêtres de contrôles dynamiquement dans une boîte de dialogue ?
Créé le 20/05/2006[haut]
auteur : Farscape
On procédera de la manière suivante :
On créera autant de boîtes de dialogue devant apparaître dans la boîte de dialogue principale.
On réglera leurs options :
style : child.
Border :None

Pour créer dynamiquement la fenêtre :

//-----------------------------------------------------------
CDialog *CSwitchDlgDlg::CreatePage(UINT nPlaceCtrlId,UINT nDialogID,CRuntimeClass *pClass/*=NULL*/)
{
    CDialog *pDlg=NULL;
    if(pClass) pDlg=reinterpret_cast<CDialog *>(pClass->CreateObject());
    else   pDlg= new CDialog;
    
    pDlg->Create(nDialogID,this);
    
    ASSERT(IsWindow(pDlg->m_hWnd));
    
    CRect rect;
    CWnd *pWnd = GetDlgItem(nPlaceCtrlId);
    ASSERT(pWnd != NULL);
    ASSERT(IsWindow(pWnd->m_hWnd));
    pWnd->GetWindowRect(&rect);
    ScreenToClient(&rect);
    pDlg->SetWindowPos(NULL, rect.left, rect.top, 0, 0, 
                        SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE );
    pDlg->EnableWindow(TRUE);
    
    return pDlg;
}
La fenêtre sera créée à l'emplacement d'un contrôle groupbox par exemple identifié par nPlaceCtrlId.
Pour basculer d'une boîte de dialogue à l'autre il suffira de faire:

// desactive
pDlg->ShowWindow(SW_HIDE);
pDlg->EnableWindow(FALSE);

// active l'autre fenetre
pDlg2->ShowWindow(SW_SHOW);
pDlg2->EnableWindow(TRUE);
On obtient ainsi un système similaire à une gestion par onglet ,mais sans le CTabCtrl...

Notes:
si un runtime de classe est passé en argument c'est un objet de cette classe qui sera créé.
permettant ainsi d'avoir une gestion personnalisée de la fenêtre fille.
Cette classe devra donc avoir les macros :

DECLARE_DYNCREATE dans le .h
IMPLEMENT_DYNCREATE dans le .cpp

Comme avec une CFormView

Pour une mise en application voir cet exemple:
http://farscape.developpez.com/Samples/SwitchDlg.zip


Comment démarrer une boîte de dialogue en mode caché ?
auteur : Farscape
Ceux qui se sont donnés la peine d'essayer de mettre un ShowWindow(SW_HIDE) dans la fonction OnInitDialog ont constaté que ça ne fonctionne pas.
Pourquoi ? En traçant le code source de CDialog on s'aperçoit qu'à la suite de OnInitDialog() il y a un appel de ShowWindow(SW_SHOW) qui réduit à néant nos efforts.

Pourtant il existe un moyen de contrer cela en interceptant le message WM_WINDOWPOSCHANGING et en enlevant le style SWP_SHOWWINDOW. Voir la fonction SetWindowPos dans MSDN.

CMyDialog::CMyDialog(CWnd* pParent /*=NULL*/)
  : CDialog(CMyDialog::IDD, pParent)
{
    /*bool*/ m_bShow = false;
}
void CMyDialog::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) 
{
  if(!m_bShow) lpwndpos->flags &= ~SWP_SHOWWINDOW;
  CDialog::OnWindowPosChanging(lpwndpos);
}
void CMyDialog::SetShowWindow()
{
 m_bShow = true;
 ShowWindow(SW_SHOW);
}
Noter la fonction SetShowWindow() qui permettra de faire apparaître le moment venu la boîte de dialogue.


Comment lancer un traitement au démarrage d'une CDialog ?
auteur : Farscape
Une précision ce post concerne le lancement d'un traitement au démarrage de la boite de dialogue, pouvant mettre à jour des éléments graphiques sans interactions clavier / souris .

Dans ce contexte placer le traitement dans OnInitDialog pose un problème la boîte de dialogue n'étant pas encore affichée le traitement risque de se dérouler mais sans afficher les interactions graphiques de la fenêtre et de ses contrôles ( affichage partiel) .
On continuera bien sûr à faire les initialisations graphiques simples dans la fonction OnInitDialog.
En conséquence le traitement doit être lancé quand la boite de dialogue est entièrement prête graphiquement, sinon le risque est de ne rien voir apparaître à l'écran.
La solution est de le déclencher au premier WM_PAINT de la fenêtre comme dans l'exemple ci-dessus.

// le header
class CTestDlg : public CDialog
{
// Construction
public:

    CTestDlg(CWnd* pParent = NULL);   // standard constructor

// Dialog Data
//{{AFX_DATA(CTestDlg)
    enum { IDD = IDD_DIALOGTEST };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA

public:
    bool  m_bFirstInit;

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTestDlg)

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
//}}AFX_VIRTUAL

LRESULT OnRunTest(UINT wParam,LONG lParam);

// Implementation
protected:
    // Generated message map functions
    //{{AFX_MSG(CTestDlg)
    afx_msg void OnPaint();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

// la partie .cpp
#define WM_RUNTEST WM_USER+100
CTestDlg::CTestDlg(CWnd* pParent /*=NULL*/)
: CDialog(CTestDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CTestDlg)
    // NOTE: the ClassWizard will add member initialization here
    //}}AFX_DATA_INIT
    m_bFirstInit=true;
}
void CTestDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CTestDlg)
    // NOTE: the ClassWizard will add DDX and DDV calls here
    //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
//{{AFX_MSG_MAP(CTestDlg)
ON_WM_PAINT()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_RUNTEST,OnRunTest)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTestDlg message handlers
void CTestDlg::OnPaint() 
{
    CPaintDC dc(this); // device context for painting
    
    // TODO: Add your message handler code here
    if(m_bFirstInit) PostMessage(WM_RUNTEST);
    m_bFirstInit=false;
    // Do not call CDialog::OnPaint() for painting messages
}
LRESULT CTestDlg::OnRunTest(UINT wParam, LONG lParam) 
{
    // votre Traitement 
    //
    //
    return 0L;
}
Voilà après initialisation de la boîte de dialogue le message privé WM_RUNTEST est envoyé pour démarrer le traitement dans la fonction OnRunTest.
Note: Il ne pas faudra pas oublier d'insérer une fonction qui laisse passer les messages pour Windows.
voir :Comment faire pour que dans une boucle de traitement l'application ne semble pas figée ?


Comment rajouter un bouton agrandir et réduire sur une CDialog ?
auteur : Farscape
Plusieurs possibilités:
Sur l'éditeur de ressources dans les propriétés de la boîte de dialogue.
A la création de la boîte de dialogue :

int CMyDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
  if(CDialog::OnCreate(lpCreateStruct) == -1)
    return -1;

  // TODO: Add your specialized creation code here
  SetWindowLong(this->m_hWnd,
                GWL_STYLE,
                GetWindowLong(this->m_hWnd, GWL_STYLE) | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);

  return 0;
}
Et enfin à la demande :

ModifyStyle(0,WS_MINIMIZEBOX | WS_MAXIMIZEBOX);

Comment faire une application boîte de dialogue sans bouton dans la barre des tâches Windows ?
auteur : Farscape
il suffit de donner le style ToolWindow à l'application.

Note :
On peut aussi donner ce style dans l'éditeur de ressources sur les propriétés de la boîte de dialogue:
onglet extended styles:cocher Tool Window.,
mais il faudra quand même enlever le style WS_EX_APPWINDOW.

Exemple d'application sur une application boîte de dialogue:

BOOL CTestToolDialogDlg::OnInitDialog()
{
CDialog::OnInitDialog();

    ModifyStyleEx( WS_EX_APPWINDOW, WS_EX_TOOLWINDOW );
...........
return TRUE;  // return TRUE  unless you set the focus to a control
}

Comment rajouter un menu à une boîte de dialogue ?
auteur : Farscape
Pour rajouter un menu à boîte de dialogue il suffit de:

  • Définir évidemment le menu dans les ressources.
  • Sélectionner les propriétés de la boîte de dialogue.
  • Dans la combobox menu sélectionner l'id du menu spécifique .

Pourquoi les notifications ON_UPDATE_COMMAND_UI ne fonctionnent pas dans une CDialog ?
Créé le 04/04/2005[haut]
auteur : Farscape
Dans le cas d'une boîte de dialogue les messages ON_UPDATE_COMMAND_UI ne sont pas effectifs.
Il faut rajouter une initialisation comme pour la classe CFrameWnd et sa fonction CFrameWnd::OnInitMenuPopup()

Extrait MSDN:

void CTestDlg::OnInitMenuPopup(CMenu *pPopupMenu, UINT nIndex,BOOL bSysMenu)
{
    ASSERT(pPopupMenu != NULL);
    // Check the enabled state of various menu items.

    CCmdUI state;
    state.m_pMenu = pPopupMenu;
    ASSERT(state.m_pOther == NULL);
    ASSERT(state.m_pParentMenu == NULL);

    // Determine if menu is popup in top-level menu and set m_pOther to
    // it if so (m_pParentMenu == NULL indicates that it is secondary popup).
    HMENU hParentMenu;
    if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu)
        state.m_pParentMenu = pPopupMenu;    // Parent == child for tracking popup.
    else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)
    {
        CWnd* pParent = this;
           // Child windows don't have menus--need to go to the top!
        if (pParent != NULL &&
           (hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)
        {
           int nIndexMax = ::GetMenuItemCount(hParentMenu);
           for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
           {
            if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu)
            {
                // When popup is found, m_pParentMenu is containing menu.
                state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
                break;
            }
           }
        }
    }

    state.m_nIndexMax = pPopupMenu->GetMenuItemCount();
    for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
      state.m_nIndex++)
    {
        state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex);
        if (state.m_nID == 0)
           continue; // Menu separator or invalid cmd - ignore it.

        ASSERT(state.m_pOther == NULL);
        ASSERT(state.m_pMenu != NULL);
        if (state.m_nID == (UINT)-1)
        {
           // Possibly a popup menu, route to first item of that popup.
           state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex);
           if (state.m_pSubMenu == NULL ||
            (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
            state.m_nID == (UINT)-1)
           {
            continue;       // First item of popup can't be routed to.
           }
           state.DoUpdate(this, TRUE);   // Popups are never auto disabled.
        }
        else
        {
           // Normal menu item.
           // Auto enable/disable if frame window has m_bAutoMenuEnable
           // set and command is _not_ a system command.
           state.m_pSubMenu = NULL;
           state.DoUpdate(this, FALSE);
        }

        // Adjust for menu deletions and additions.
        UINT nCount = pPopupMenu->GetMenuItemCount();
        if (nCount < state.m_nIndexMax)
        {
           state.m_nIndex -= (state.m_nIndexMax - nCount);
           while (state.m_nIndex < nCount &&
            pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
           {
            state.m_nIndex++;
           }
        }
        state.m_nIndexMax = nCount;
    }
} 


Comment rendre transparente une boîte de dialogue ?
Créé le 20/05/2006[haut]
auteur : Farscape
Pour disposer du mode transparent disponible à partir de win2000 on fera comme suit:

- Définir #define _WIN32_WINNT 0x0500 dans stdafx.h
- Rajouter le style étendu WS_EX_LAYERED à la boîte de dialogue.
Intercepter le message CtlColor au niveau de la boîte de dialogue et fournir une brosse (solid brush) pour la couleur de transparence.
- Appeler l'api32 SetLayeredWindowAttributes dans OnInitDialog .
- consulter MSDN pour voir le réglage des options.

Exemple :

BOOL CAboutDlg::OnInitDialog() 
{
    CDialog::OnInitDialog();

// TODO: Add extra initialization here

m_pBrush= new CBrush;
m_pBrush->CreateSolidBrush(RGB(187,221,255));

ModifyStyleEx(0,WS_EX_LAYERED);
SetLayeredWindowAttributes(m_hWnd,RGB(187,221,255),180,LWA_ALPHA);

return TRUE;  // return TRUE unless you set the focus to a control
              // EXCEPTION: OCX Property Pages should return FALSE
}
HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
//HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: Change any attributes of the DC here
// TODO: Return a different brush if the default is not desired
return static_cast<HBRUSH>(*m_pBrush);
//return hbr;
}
Note:Avec visual 6.0 il faut disposer d'un SDK à jour .


Comment mettre une image de fond dans une boîte de dialogue ?
auteur : Farscape
Il faut intercepter le message WM_ERASEBKGND
Note : dans le cas d'une boîte de dialogue :
Avec Classwizard modifier le type de fenêtre dans l'onglet class info et sélectionner dans la combobox « message filter » l'option « child window » .
Sinon le message n'apparaîtra pas dans la liste?..

Pour les besoins de l'exemple j'ai fait simple, je m'appuie sur un exemple de lecture d'image à partir de l'objet IPicture.
Le lien pour la classe CPicture :
http://www.codeguru.com/bitmap/CPicture.html

// la classe Dialog :
class CTestsDiversDlg : public CDialog
{
// Construction
public:
CTestsDiversDlg(CWnd* pParent= NULL);// standard constructor

// Dialog Data
//................................................
CPicture m_Picture; // la variable picture

// Implementation
protected:

// Generated message map functions
//{{AFX_MSG(CTestsDiversDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg BOOL OnEraseBkgnd(CDC* pDC); // le message
//}}AFX_MSG

DECLARE_MESSAGE_MAP()
};
//-----------------------------------------------------------------------------------
// le code
BEGIN_MESSAGE_MAP(CTestsDiversDlg, CDialog)
//{{AFX_MSG_MAP(CTestsDiversDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_ERASEBKGND() // le message rajoute par classwizard
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CTestsDiversDlg::OnEraseBkgnd(CDC* pDC) 
{
    // TODO: Add your message handler code here and/or call default
    if(m_Picture.m_IPicture)   
    {
        CRect rect;
        GetClientRect(&rect);
        m_Picture.UpdateSizeOnDC(pDC); // Get Picture Dimentions In Pixels

        m_Picture.Show(pDC, CPoint(0,0), CPoint(m_Picture.m_Width,
                        m_Picture.m_Height), 0,0);
        m_Picture.Show(pDC,rect); // Change Original Dimentions 

        return FALSE;
    }   
    return CDialog::OnEraseBkgnd(pDC);
}

Comment faire pour qu'un projet boîte de dialogue soit toujours en avant plan ?
auteur : Farscape
il suffit de rajouter la séquence suivante dans la fonction OnInitDialog :

BOOL CTestDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
 // ....................................
 //........................................
    CRect rect;
    GetWindowRect( rect );
    ::SetWindowPos(m_hWnd ,
                    HWND_TOPMOST,
                    rect.left,      
                    rect.top,       
                    rect.Width(),
                    rect.Height(),  
                    SWP_SHOWWINDOW);

    return TRUE;  // return TRUE  unless you set the focus to a control
}

Comment imprimer une boite de dialogue ?
Mise à jour le 20/01/2005[haut]
auteur : Farscape
Méthode:
Générer un bitmap avec la portion d'écran souhaitée:
Note MSDN:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_5a5h.asp

Imprimer le bitmap:
Un problème se pose:
Le bitmap généré représente un DDB :device-dependent bitmap . Et ce type de bitmap n'est pas imprimable directement ,il faudra le transformer en DIB device-independent bitmap.
d'où l'utilisation dans mon exemple de la classe CPictureHolder .
Le même problème sera rencontré avec l'utilisation de la fonction CBitmap::LoadBitmap, pour contourner le problème il faudra faire comme suit:

VERIFY (bm.Attach (::LoadImage (::AfxFindResourceHandle(
 MAKEINTRESOURCE (inBitmapID), RT_BITMAP),
 MAKEINTRESOURCE (inBitmapID), IMAGE_BITMAP, 0, 0,
 (LR_DEFAULTSIZE | LR_CREATEDIBSECTION))))

#include <afxctl.h>

CBitmap *CopyScreenToBitmap(LPRECT lpRect)
{
    CDC     SrcDC, MemDC;
    int     nX, nY, nX2, nY2;      
    int     nWidth, nHeight;       
    int     xScrn, yScrn;          
    
    CBitmap *   pOldBitmap ,*pBitmap;
    
    if (IsRectEmpty(lpRect)) return NULL;      
    
    SrcDC.CreateDC("DISPLAY", NULL, NULL, NULL);        
    MemDC.CreateCompatibleDC(&SrcDC);
    
    nX = lpRect->left;     
    nY = lpRect->top;     
    nX2 = lpRect->right;     
    nY2 = lpRect->bottom;
    
    xScrn = SrcDC.GetDeviceCaps(HORZRES);     
    yScrn = SrcDC.GetDeviceCaps(VERTRES);      
    
    if (nX < 0) nX = 0;        
    if (nY < 0) nY = 0;     
    if (nX2 > xScrn) nX2 = xScrn;      
    if (nY2 > yScrn) nY2 = yScrn;      
    nWidth = nX2 - nX;     
    nHeight = nY2 - nY;      
    
    pBitmap=new CBitmap;
    pBitmap->CreateCompatibleBitmap(&SrcDC,nWidth, nHeight);      
    
    pOldBitmap =MemDC.SelectObject (pBitmap);          
    MemDC.BitBlt(0, 0, nWidth, nHeight, &SrcDC, nX, nY, SRCCOPY);     
    
    pBitmap = MemDC.SelectObject( pOldBitmap);       
    MemDC.DeleteDC();     
    SrcDC.DeleteDC();      
    
    return (pBitmap); 
}

CBitmap *CopyWindowToBitmap(CWnd* pWnd ,bool bWindowClient)
{
    CBitmap *pBitmap=NULL;
    if(!pWnd->m_hWnd) return NULL;
    
    RECT    rectWnd; 
    pWnd->GetWindowRect(&rectWnd);
    if(!bWindowClient) return CopyScreenToBitmap(&rectWnd);
    
    RECT rectClient;             
    POINT pt1, pt2;             
    pWnd->GetClientRect(&rectClient);
    pt1.x = rectClient.left;             
    pt1.y = rectClient.top;             
    pt2.x = rectClient.right;             
    pt2.y = rectClient.bottom;             
    
    pWnd->ClientToScreen(&pt1);             
    pWnd->ClientToScreen(&pt2);             
    rectClient.left = pt1.x;             
    rectClient.top = pt1.y;             
    rectClient.right = pt2.x;             
    rectClient.bottom = pt2.y;  
    
    return CopyScreenToBitmap(&rectClient);   
}
void PrintBmp(CBitmap *pBmp)
{
    // mise a jour le 15/01/2005 :ajuste le bitmap sur la totalité de la feuille et edite en mode paysage. 
    CDC             dc;
    CPrintDialog    printDlg(FALSE);
    
    // selection de l'imprimante.
    if (printDlg.DoModal() == IDCANCEL)   return;
    
    DEVMODE FAR *pDevMode=(DEVMODE FAR *)::GlobalLock(printDlg.GetDevMode());
    
    // set orientation to landscape
    pDevMode->dmOrientation=DMORIENT_LANDSCAPE;
    ::GlobalUnlock(printDlg.GetDevMode());
    
    HDC hdc =printDlg.CreatePrinterDC();
    
    //dc.Attach(printDlg.GetPrinterDC()); sinon le mode paysage ne fonctionne pas
    
    dc.Attach(hdc);
    dc.m_bPrinting = TRUE; // dc d'impression.
    
    // titre du document = titre application
    CString strTitle;   
    strTitle.LoadString(AFX_IDS_APP_TITLE);
    
    DOCINFO di;
    ::ZeroMemory (&di, sizeof (DOCINFO));
    
    di.cbSize = sizeof (DOCINFO);   
    di.lpszDocName = strTitle;
    
    // debut d'impression
    if(dc.StartDoc( &di ))
    {     
        // debut page
        dc.StartPage();
        
        // surface d'impression
        CRect rectDraw;
        rectDraw.SetRect(0, 0,
            dc.GetDeviceCaps(HORZRES),
            dc.GetDeviceCaps(VERTRES));
        
        // infos bitmap
        BITMAP bmpInfo;
        pBmp->GetBitmap(&bmpInfo);
        
        // creation d'un objet CPictureHolder pour avoir un dib.
        CPictureHolder picture;
        picture.CreateFromBitmap(pBmp);
        
        // rectangle d'impression      
        int ncoefy=(rectDraw.Height()/bmpInfo.bmHeight);
        
        // centrer l'image sur la feuille
        int nX = rectDraw.left + (rectDraw.Width() - (bmpInfo.bmWidth*ncoefy)) / 2;
        int nY = rectDraw.top + (rectDraw.Height() - (bmpInfo.bmHeight*ncoefy)) / 2;
        
        CRect rect;      
        rect.SetRect(CPoint(nX,nY),CPoint(nX+(bmpInfo.bmWidth*ncoefy),nY+(bmpInfo.bmHeight*ncoefy)));
        
        // affichage final
        picture.Render(&dc,rect,rect);
        
        dc.EndPage(); // fin de page
        dc.EndDoc();  // fin du document
    }   
    else dc.AbortDoc(); // erreur d'impression
    dc.Detach();        // liberation dc d'impression.
    DeleteObject(hdc); 
}

// contexte d'utilisation : dans une boite de dialogue ou view etc..
CBitmap *pBmp=CopyWindowToBitmap(this,true);
PrintBmp(pBmp);    
pBmp->DeleteObject();
delete pBmp;

Comment créer une boîte de dialogue non modale ?
Créé le 22/01/2007[haut]
auteur : Farscape
On procédera comme avec une boîte de dialogue modale classique pour sa création dans les ressources.
Seul l'appel différera :

pDlg = new CMyDlg(this);
pDlg->Create(CMyDlg ::IDD,this);
pDlg->ShowWindow(SW_SHOW);

lien : faq Comment libérer la mémoire sur une fenêtre dynamique ?

Comment libérer la mémoire sur une fenêtre dynamique ?
auteur : Farscape
Le cas typique est l'utilisation d'une boite de dialogue non modale.
Exemple :

pDlg = new CMyDlg(this);
pDlg->Create(CMyDlg ::IDD,this);
pDlg->ShowWindow(SW_SHOW);
Dans ces conditions où placer le delete de pDlg ?
Les MFC disposent d'une fonction spécifique pour réaliser ce traitement :

CWnd::PostNcDestroy
virtual void PostNcDestroy( );
Cette fonction est appelée par la fonction membre OnNcDestroy après la destruction de la fenêtre.
Les classes dérivées peuvent utiliser cette fonction pour effectuer la suppression du pointeur this.

void CMyDlg :: PostNcDestroy( )
{
CDialog::PostNcDestroy();
delete this;
}
Pour plus d'informations consulter la note MSDN :TN017: Destroying Window Objects


Comment est calculée l'unité de mesure d'une boîte de dialogue ?
auteur : Farscape
L'unité de base horizontale pour une boîte de dialogue est égale à la taille moyenne d'un caractère avec la fonte "Système".
Pour l'équivalence en pixels on utilise la formule suivante:

pixelX = (dialogunitX * baseunitX) / 4
pixelY = (dialogunitY * baseunitY) / 8
Exemple:

BOOL CAboutDlg::OnInitDialog() 
{
CDialog::OnInitDialog();

        // TODO: Add extra initialization here

   CRect rc( 0, 0, 4, 8 );
   MapDialogRect( &rc );
   int baseUnitY = rc.bottom;
   int baseUnitX = rc.right;
   TRACE("baseUnitX = %d\n", baseUnitX );
   TRACE("baseUnitY = %d\n", baseUnitY );

// si ma boîte de dialogue fait 300 x 300 unité on aura :

   TRACE("PixelX = %d\n", (baseUnitX *300)/4); 
   TRACE("PixelY = %d\n", (baseUnitY *300)/8 );

    return TRUE;  // return TRUE unless you set the focus to a control
                // EXCEPTION: OCX Property Pages should return FALSE
}
Ceci est valable pour une fonte "Système" sinon se reporter à la note MSDN: http://support.microsoft.com/default.aspx?scid=kb;en-us;125681
Voir aussi:
http://support.microsoft.com/default.aspx?scid=kb;en-us;145994
Note :
Dans le cas où on voudrait établir une correspondance directe à la conception avec le nombre de pixels,
On peut régler la fonte "Système" de la boîte de dialogue à 10 points,
Après on aura : X pixels = 2 * unité boîte de dialogue.
Pour l'exemple précédent d'une boîte de dialogue de 300 x 300 unités on obtiendra 600*600 pixels ...


Comment afficher une CDialog depuis une DLL?
Créé le 27/11/2005[haut]
auteur : matazz
Pour afficher une boîte de dialogue depuis une DLL, il faut d'abord avoir choisi un projet DLL extension MFC ou avoir rajouté le support MFC dans votre DLL.

Après il suffit simplement d'appeller AFX_MANAGE_STATE :

AFX_MANAGE_STATE(AfxGetStaticModuleState());
CMyLocalDialog dlg;
dlg.DoModal();


Quand appeler la macro AFX_MANAGE_STATE(AfxGetStaticModuleState( )) ?
Créé le 27/11/2005[haut]
auteur : Farscape
La DLL MFC (MFC42.DLL) est chargée en tant qu'élément d'un processus et elle stocke des données dans des variables globales.
Si les fonctions MFC sont appelées depuis le programme ou d'une DLL d'extension la DLL MFC sait modifier ces variables pour le processus.
Par contre dans le cas d'une DLL classique cette macro est à appeler chaque fois que l'on appelle des fonctions de MFC42.dll.
Sinon les variables globales ne sont pas synchronisées et on a un comportement indéfini.
Note si les MFC sont liées statiquement la macro n'a aucun effet..


Comment créer une boîte de dialogue dynamiquement sans ressources ?
Créé le 27/11/2005[haut]
auteur : Farscape

// .h 
class CDynamicDlg : public CDialog
{
// Construction
public:
DECLARE_DYNCREATE(CDynamicDlg)
CDynamicDlg();
CDynamicDlg(int x,int y,int cx,int cy,const char *szTitle,CWnd* pParent = NULL);// standard constructor

    ~CDynamicDlg();
// Dialog Data
//{{AFX_DATA(CDynamicDlg)
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
void SetDynamicDlg(int x,int y,int cx,int cy,const char *szTitle,CWnd* pParent = NULL);
// Implementation
private:
HGLOBAL m_hgbl;
protected:

// Generated message map functions
//{{AFX_MSG(CDynamicDlg)
// NOTE: the ClassWizard will add member functions here
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
// .cpp
/////////////////////////////////////////////////////////////////////////////
// CDynamicDlg dialog

IMPLEMENT_DYNCREATE(CDynamicDlg,CDialog)

CDynamicDlg::CDynamicDlg()
{
    m_hgbl=NULL;
}
CDynamicDlg::CDynamicDlg(int x,int y,int cx,int cy,const char *szTitle,CWnd* pParent /*=NULL*/)
: CDialog()
{
    //{{AFX_DATA_INIT(CDynamicDlg)
    // NOTE: the ClassWizard will add member initialization here
    //}}AFX_DATA_INIT 
    m_hgbl=NULL;
    SetDynamicDlg(x,y,cx,cy,szTitle,pParent);
}

void CDynamicDlg::SetDynamicDlg(int x,int y,int cx,int cy,const char *szTitle,CWnd* pParent /*=NULL*/)
{
    // 
    LPDLGTEMPLATE lpdt;
    LPWORD lpw;
    
    if(m_hgbl) GlobalFree(m_hgbl);
    m_hDialogTemplate=NULL;
    m_hgbl=GlobalAlloc(GMEM_ZEROINIT,1024);
    lpdt = (LPDLGTEMPLATE)GlobalLock(m_hgbl);
    
    lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION;
    lpdt->cdit = 0;
    lpdt->x = x;
    lpdt->y = y;
    lpdt->cx = cx;
    lpdt->cy = cy;
    lpw=(LPWORD) (lpdt+1);
    *lpw++=0;
    *lpw++=0;
    while(*szTitle) *lpw++=*szTitle++;
    *lpw++=0;
    
    GlobalUnlock(m_hgbl);
    InitModalIndirect(m_hgbl);
}
 
CDynamicDlg::~CDynamicDlg()
{
    if(m_hgbl) GlobalFree(m_hgbl);
} 

BEGIN_MESSAGE_MAP(CDynamicDlg, CDialog)
//{{AFX_MSG_MAP(CDynamicDlg)
// NOTE: the ClassWizard will add message map macros here
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDynamicDlg message handlers
Utilisation:

CDynamicDlg dlg;
dlg.SetDynamicDlg(0,0,100,200,"essai",this);
dlg.DoModal();
il ne reste plus qu'à l'habiller dynamiquement en créant les contrôles dans la fonction OnInitDialog initiée par le message WM_INITDIALOG.


Comment copier une boîte de dialogue d'un projet à un autre ?
Créé le 20/05/2006[haut]
auteur : Farscape
A partir du projet de destination, ouvrir le fichier .RC du projet d'origine (file open avec VC6.0)
Sélectionnez la ou les boîtes de dialogues concernées, placez la sélection dans le presse-papiers.
(CTRL+INS ou ctrl+C ou clic droit copier) ,
Placez ensuite la souris dans le dossier dialogue du projet de destination pour insérer les dialogues par le bouton coller (ou Maj + INS ou CTRL+V)
On procédera de la même manière pour les barres d'outils (toolbars) et les bitmaps.


Comment partager des données entre une CFormView et une CDialog ?
Créé le 22/01/2007[haut]
auteur : Farscape
Si j'ai pris cet exemple c'est parce qu'il représente la majorité des cas pratiques rencontrés
Le problème :

Une boîte de dialogue est lancée à partir d'une CFormView .
Dans cette boîte de dialogue j'ai besoin d'accéder et de partager l'accès à une variable quelconque située dans ma CFormView .
Comment faire ? , On peut envisager de passer un pointeur et de manipuler celui-ci dans la dialogue.
Pourquoi ne pas passer l'argument directement comme une référence ?

Exemple:
Je vais partager une variable conteneur de type CStringList entre ma CFormView et ma CDialog.

Ma classe dialogue:

class CTestDlg : public CDialog
{
// Construction
public:
    // le constructeur d'origine est modifié pour le passage de la variable a partager.
    CTestDlg(CStringList &rStringList,CWnd* pParent = NULL);   // standard constructor

// Dialog Data
    //{{AFX_DATA(CTestDlg)
    enum { IDD = IDD_DIALOG1 };
        // NOTE: the ClassWizard will add data members here
    //}}AFX_DATA

CStringList &m_rStringList; // la donnée membre dans la dialogue.

Le code de ma boîte de dialogue regardez bien le constructeur :

CTestDlg::CTestDlg(CStringList &rStringList,CWnd* pParent /*=NULL*/)
    : CDialog(CTestDlg::IDD, pParent),m_rStringList(rStringList)
{
    //{{AFX_DATA_INIT(CTestDlg)
        // NOTE: the ClassWizard will add member initialization here
    //}}AFX_DATA_INIT
}
BOOL CTestDlg::OnInitDialog() 
{
    CDialog::OnInitDialog();
    
    // TODO: Add extra initialization here
// j'affiche en debug le contenu de mon containeur 
#ifdef _DEBUG
   for(POSITION pos = m_rStringList.GetHeadPosition(); pos != NULL; )
   {
    afxDump << m_rStringList.GetNext( pos ) << "\n";
   }
#endif
    // je rajoute un élément
    m_rStringList.AddTail("essai dlg");
    return TRUE;  // return TRUE unless you set the focus to a control
                  // EXCEPTION: OCX Property Pages should return FALSE
}

Le code d'appel dans ma CFormView:

void CTestToolBarView::OnInitialUpdate()
{
    CFormView::OnInitialUpdate();
    ResizeParentToFit();

    CStringList rStringList;

    rStringList.AddTail("essai");
    rStringList.AddTail("essai2");
    rStringList.AddTail("essai3");

    CTestDlg Dlg(rStringList);// passage de la variable dans le constructeur.
    Dlg.DoModal();

   // affichage du containeur
    #ifdef _DEBUG
    for(POSITION pos = rStringList.GetHeadPosition(); pos != NULL; )
    {
     afxDump << rStringList.GetNext( pos ) << "\n";
    }
#endif
}
Voilà je peux accéder à ma variable dans boîte de dialogue naturellement sans pointeur et interagir dessus comme le montre mon exemple ci-dessus.


Comment afficher une boîte de dialogue à des coordonnées choisies ?
Créé le 22/01/2007[haut]
auteur : Farscape
Le lancement d'une boîte de dialogue ne permet pas de spécifier l'emplacement de celle-ci à l'écran.
On peut tout au plus spécifier que la boîte de dialogue sera centrée en réglant l'option sur la propriété de la fenêtre dans le gestionnaire de ressources.

Il existe pourtant une possibilité méconnue: lire le template (DLGTEMPLATE) de la dialogue et modifier son contenu?
Pour cela j'utiliserai une classe MFC non documentée (CDialogTemplate) qui permet en outre de changer la police de la boîte de dialogue avant son affichage :


#include <afxpriv.h>
int CDlgMyDlg::DoModal(int x,int y)
{
   CDialogTemplate dlgTemp;
   int             nResult;

   // lecture du template d'origine
   if (!dlgTemp.Load(MAKEINTRESOURCE(IDD))) return -1;

  
   // fonte par defaut
//   dlgTemp.SetFont("MS Sans Serif", 8); eventuel changement de fonte

   // pointeur sur le dialogue template modifié
   LPSTR pdata = reinterpret_cast<LPSTR>(GlobalLock(dlgTemp.m_hTemplate));

   DLGTEMPLATE* pTemplate = reinterpret_cast<DLGTEMPLATE*>(pdata);

   pTemplate->x=x; // changement des coordonnées x,y
   pTemplate->y=y;

   m_lpszTemplateName = NULL;
   InitModalIndirect(pdata);

   // appel domodal 
   nResult = CDialog::DoModal();

   // liberation du template modifié
   GlobalUnlock(dlgTemp.m_hTemplate);

   return nResult;
La classe CDialogTemplate est définie dans le fichier afxpriv.h.

Comment procéder :
rajouter à votre classe boîte de dialogue la fonction DoModal écrite ci-dessus.
Note: Celle-ci finit par rappeler la fonction DoModal de la classe CDialog

il ne reste plus qu'a appeler votre boîte de dialogue comme suit:

CDlgMyDlg Dlg;
Dlg.DoModal(100,200);



Comment mettre en place un raccourci clavier dans une boîte de dialogue ?
Créé le 22/01/2007[haut]
auteur : Farscape
Le traitement des raccourcis claviers n'est pas pris en charge dans une boîte de dialogue.
Pour le rendre effectif on procédera comme suit :
Dans la classe CDialog héritée on commencera par déclarer une variable de type HACELL ;

HACCEL  m_hTable;

Ensuite dans la fonction OnInitDialog on va lire la table d'accélérateurs souhaitée:

m_hTable = LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));

Enfin il faut ajouter la fonction PreTranslateMessage avec l'assistant et mettre le code qui suit pour relayer les messages.



BOOL CMyDialog::PreTranslateMessage(MSG* pMsg)
 {
   if (m_hTable  && ::TranslateAccelerator(m_hWnd, m_hTable, pMsg))
              return(TRUE);
      return CDialog::PreTranslateMessage(pMsg);
}

Comment implémenter le tab stop entre deux boîtes de dialogue imbriquées ?
Créé le 22/01/2007[haut]
auteur : Farscape
Dans le cas où on imbriquerait une autre boîte de dialogue sur une boîte de dialogue existante le problème de la gestion de l'ordre de tabulation entre les deux fenêtres apparaît.

Comment gérer le passage naturel par la touche tab stop entre les deux fenêtres ?
La fenêtre fille devra disposer du style WM_CHILD mais aussi du style DS_CONTROL.
ce dernier permettra à la boîte de dialogue de fonctionner comme une fenêtre enfant dans la boîte de dialogue principale permettant ainsi la gestion du tab stop à travers les fenêtres voir MSDN

Ce style est réglable dans les propriétés de la boîte de dialogue dans l'éditeur de ressources.

Note:Si le parent de la boîte de dialogue est un contrôle situé dans la boîte de dialogue principale, il faudra rajouter le style WS_EX_CONTROLPARENT à ce contrôle,

Exemple :
J'ai une boîte de dialogue DlgOne qui possède un contrôle static nommé ancre qui me permet d'afficher une autre boîte de dialogue DlgTwo dans DlgOne.

BOOL
DlgOne::OnInitDialog()
{
    CDialog::OnInitDialog();
    ancre.ModifyStyleEx(0, WS_EX_CONTROLPARENT);
    DlgTwo.Create(IDD_DIAGTWO, &ancre);
    
}




Comment savoir si une boîte de dialogue non modale est active ?
Créé le 17/09/2007[haut]
auteur : Farscape
Le problème :
Je dispose d'une boîte de dialogue non modale qui ne doit être lancée qu'une seule fois dans mon application.
Dans ce contexte comment savoir si la boîte de dialogue est déjà lancée et accessoirement comment récupérer un pointeur sur cette fenêtre ?

Réponse: En la cherchant dans les fenêtres de mon application.

Exemple pour une CDialog nommée CDlgTest:
il faudra rajouter manuellement à notre boîte de dialogue le couple de macros DECLARE_DYNCREATE et IMPLEMENT_DYNCREATE pour la reconnaissance de signature:

Le .h:

class CDlgTest : public CDialog
{
// Construction
public:
    DECLARE_DYNCREATE(CDlgTest)
    CDlgTest(CWnd* pParent = NULL);   // standard constructor
/....
Le .cpp:

/////////////////////////////////////////////////////////////////////////////
// CDlgTest dialog

IMPLEMENT_DYNCREATE(CDlgTest, CDialog)
CDlgTest::CDlgTest(CWnd* pParent /*=NULL*/)
    : CDialog(CDlgTest::IDD, pParent)
{
    //{{AFX_DATA_INIT(CDlgTest)
    //}}AFX_DATA_INIT
}
L'appel de la dialogue:

    CDlgTest *pDlg;
    pDlg = new CDlgTest();
    pDlg->Create(CDlgTest ::IDD,AfxGetMainWnd());
    pDlg->ShowWindow(SW_SHOW);
Sa recherche:

CWnd* pChild;        
    pChild = AfxGetMainWnd()->GetWindow(GW_HWNDFIRST);
    while (pChild != NULL)
    {
        if(pChild->IsKindOf(RUNTIME_CLASS(CDlgTest)))
        {
            TRACE("\nCDialog Find:%x,%x",pChild,pChild->m_hWnd); // la dialogue est trouvée !!!
            break;
        }
        pChild = pChild->GetWindow(GW_HWNDNEXT);
    }

Comment donner le focus à un contrôle dans OnInitDialog ?
Créé le 07/07/2008[haut]
auteur : Farscape
La méthode OnInitdialog doit renvoyer un BOOLEEN en sortie :

BOOL CSimpleDlg::OnInitDialog()
{
   CDialog::OnInitDialog();

   // TODO: Add extra initialization here
   m_cMyEdit.SetWindowText(_T("My Name")); // Initialize control values
   m_cMyList.ShowWindow(SW_HIDE);      // Show or hide a control, etc.

   return TRUE;  // return TRUE unless you set the focus to a control
   // EXCEPTION: OCX Property Pages should return FALSE
}
Par défaut celle-ci renvoie true.
Dans le cas où on voudrait donner le focus à un contrôle spécifique il faudra appliquer SetFocus sur ce contrôle et renvoyer FALSE.

BOOL CSimpleDlg::OnInitDialog()
{
   CDialog::OnInitDialog();

   // TODO: Add extra initialization here
   m_cMyEdit.SetWindowText(_T("My Name")); // Initialize control values
   m_cMyEdit.SetFocus();

   return FALSE;  // return TRUE unless you set the focus to a control
   // EXCEPTION: OCX Property Pages should return FALSE
}


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.