IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ VC++ et MFCConsultez toutes les FAQ

Nombre d'auteurs : 20, nombre de questions : 545, 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

SommaireClasses Fenêtres et FrameWorkTraitements sur la MDI (15)
précédent sommaire suivant
 

La gestion de plusieurs fenêtres dans un projet MDI passe par la déclaration dans la fonction InitInstance (classe d'application CWinApp ) d'objets de la classe CMultiDocTemplate.

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
  
BOOL CTestMdiApp::InitInstance() 
{ 
    AfxEnableControlContainer(); 
    #ifdef _AFXDLL 
    Enable3dControls();// Call this when using MFC in a shared DLL 
    #else 
    Enable3dControlsStatic();// Call this when linking to MFC statically 
    #endif 
  
// Change the registry key under which our settings are stored. 
// TODO: You should modify this string to be something appropriate 
// such as the name of your company or organization. 
    SetRegistryKey(_T("Local AppWizard-Generated Applications")); 
  
    LoadStdProfileSettings(); 
    // Load standard INI file options (including MRU) 
    // Register the application's document templates.  Document templates 
    //  serve as the connection between documents, frame windows and views. 
    // CMultiDocTemplate *m_pTplMdiView; 
    m_pTplMdiView = new CMultiDocTemplate ( 
                            IDR_TESTMDTYPE, 
                            RUNTIME_CLASS(CTestMdiDoc), 
                            // custom MDI child frame 
                            RUNTIME_CLASS(CChildFrame),  
                            RUNTIME_CLASS(CTestMdiView)); 
                            AddDocTemplate(m_pTplMdiView); 
  
    // deuxième document  
    // stockage du CMultiDocTemplate dans la classe application pour appel ultérieur. 
    // CMultiDocTemplate * m_pTplEditView; dans le header. 
    m_pTplEditView= new CMultiDocTemplate ( 
                            IDR_TESTMDTYPE, 
                            RUNTIME_CLASS(CTestMdiDoc), 
                            // custom MDI child frame 
                            RUNTIME_CLASS(CChildFrame),  
                            RUNTIME_CLASS(CEditView)); 
                            AddDocTemplate(m_pTplEditView); 
    // create main MDI Frame window 
    CMainFrame* pMainFrame= new CMainFrame; 
    if(!pMainFrame->LoadFrame(IDR_MAINFRAME)) 
        return FALSE; 
    m_pMainWnd = pMainFrame; 
  
    // Parse command line for standard shell commands, DDE, file open 
    CCommandLineInfo cmdInfo; 
    ParseCommandLine(cmdInfo); 
  
    // Dispatch commands specified on the command line 
    if(!ProcessShellCommand(cmdInfo)) return FALSE; 
  
    // The main window has been initialized, so show and update it. 
    pMainFrame->ShowWindow(m_nCmdShow); 
    pMainFrame->UpdateWindow(); 
  
    return TRUE; 
}
Ci-dessus on a une déclaration classique pour gérer deux fenêtres différentes au sein du même programme.
La création de la deuxième fenêtre pourra se faire comme suit :

Code c++ : Sélectionner tout
1
2
  
((CTestMdiApp  *)AfxGetApp())->m_pTplEditView->OpenDocumentFile(NULL) ;

Mis à jour le 5 avril 2013 farscape

D'abord pour fixer les idées, dans quel cas a-t-on besoin d'avoir des fenêtres différentes pour un même document ?
Chaque fois que l'on voudra avoir un lien entre plusieurs fenêtres pour des échanges de données ou des représentations de données d'une manière différente, le document donnant, par ses méthodes, un point d'accès pratique et facile aux différentes fenêtres.
Exemple :
Dans une « CFormView » je saisis des données pour l'affichage d'un graphe,dans une CView je les dessine sous forme de tableau récapitulatif , et dans une autre « CView » je les représente sous forme de diagrammes ,histogrammes etc..

L'association de plusieurs fenêtres sur un seul document s'effectue sur la déclaration du document template dans la fonction InitInstance de la classe d'application.

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
  
/* 
à declarer dans la classe app en tant que données membres 
CMultiDocTemplate* m_pTwoDocTemplate; 
CMultiDocTemplate* m_pFirstTemplate; 
*/ 
// La définition principale 
m_pFirstTemplate= new CMultiDocTemplate(IDR_TESTMDTYPE, 
                                        RUNTIME_CLASS(CTestMdiDoc), 
                                         // custom MDI child frame 
                                        RUNTIME_CLASS(CChildFrame), 
                                        RUNTIME_CLASS(CTestMdiView)); 
                                        AddDocTemplate(m_pFirstTemplate); 
  
// la fenêtre supplémentaire. 
m_pTwoDocTemplate=new CMultiDocTemplate(IDR_TESTMDTYPE, 
                                        RUNTIME_CLASS(CTestMdiDoc), 
                                        // custom MDI child frame 
                                        RUNTIME_CLASS(CChildFrame),  
                                        RUNTIME_CLASS(CMyEditView)); 
// pas de AddocTemplate.
Ici le premier document template comprend une « CView » et la fonction AddocTemplate est appelée
le deuxième juste une déclaration du template sans faire l'appel à AddDocTemplate .
Pour rajouter un objet de la class CMyEditView par exemple dans la fonction OnInitialUpdate de la classe CTestMdiView on procédera comme suit:

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
  
void CTestMdiView::OnInitialUpdate()  
{ 
    CView::OnInitialUpdate(); 
    // TODO: Add your specialized code here and/or call the base class 
    CTestMdiApp *TheApp=(CTestMdiApp*)AfxGetApp(); 
    CFrameWnd * pFrame =TheApp->m_pTwoDocTemplate->CreateNewFrame(GetDocument(),GetParentFrame()); 
   TheApp->m_pFirstTemplate->InitialUpdateFrame(pFrame,GetDocument());  
}
Le même appel pouvant être fait en réponse à une commande sur un menu sur la view en cours.( CTestMdiView).
Les étapes du traitement:
Récupération de la classe application pour accéder au pointeur sur document template (m_pFirstTemplate)
Création d'une « Mdi » à partir du deuxième document template (m_pTwoDocTemplate)
Rattacher la MDI avec sa fenêtre CMyEditView au premier document template avec la fonction InitialUpdateFrame .

On répétera le même processus pour la description et la création d'une fenêtre supplémentaire.
Au final on aura bien un objet document avec plusieurs Fenêtres.
C'est vérifiable par exemple en parcourant les fenêtres à partir de l'objet document :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  
void CMyEditView::OnInitialUpdate()  
{ 
    CEditView::OnInitialUpdate(); 
  
    // TODO: Add your specialized code here and/or call the base class 
    POSITION pos=GetDocument()->GetFirstViewPosition(); 
   CView *pView; 
   do 
   { 
          pView=GetDocument()->GetNextView(pos); 
   } 
   while(pView); 
}
Cette méthode permet de gérer l'apparition de fenêtres rattachées au même document à la demande..
Notes:
On n'est pas pour autant obligé de stocker des données communes dans le document.
Le document n'a pas de partie graphique visible.

Mis à jour le 5 avril 2013 farscape

En passant par les fonctions de la CMDIChildWnd .
A partir de la fenêtre fille dans la fonction OnInitialUpdate() on commence par récupérer le pointeur sur la MDI avec la fonction GetParentFrame() pour appeler MDIMaximize( );

Code c++ : Sélectionner tout
1
2
  
((CMDIChildWnd *)GetParentFrame())->MDIMaximize( );

Mis à jour le 5 avril 2013 farscape

En passant par les fonctions de la CMDIChildWnd .
A partir de la fenêtre fille dans la fonction OnInitialUpdate() on commence par récupérer le pointeur sur la MDI avec la fonction GetParentFrame() pour appeler MDIRestore( );

Code c++ : Sélectionner tout
1
2
  
((CMDIChildWnd *)GetParentFrame())->MDIRestore( );

Mis à jour le 5 avril 2013 farscape

Code c++ : Sélectionner tout
1
2
3
  
CMDIFrameWnd::MDIGetActive  
CMDIChildWnd* MDIGetActive( BOOL* pbMaximized = NULL ) const;
Exemple d'application maximiser la child active .
On commence par récupérer le pointeur sur la MainFrame avec AfxGetMainWnd().

Code c++ : Sélectionner tout
1
2
3
4
5
  
BOOL maximized; 
CMDIChildWnd* child =((CMDIFrameWnd *)AfxGetMainWnd())->MDIGetActive(&maximized); 
if (child && (!maximized)) 
      child->MDIMaximize();   // ou MDIMaximize(child);

Mis à jour le 5 avril 2013 farscape

En utilisant la fonction IsIconic() de la classe CWnd.

Code c++ : Sélectionner tout
1
2
3
4
  
CWnd::IsIconic 
BOOL IsIconic( )  
const;
Exemple de restauration d'une MDI iconisée

Code c++ : Sélectionner tout
1
2
3
4
5
  
 BOOL maximized; 
   CMDIChildWnd* child =((CMDIFrameWnd *)AfxGetMainWnd())-> MDIGetActive(&maximized); 
   if (child && (maximized || child->IsIconic())) 
     child->MDIRestore();     // ou ((CMDIFrameWnd *)AfxGetMainWnd())->MDIRestore(child);

Mis à jour le 5 avril 2013 farscape

En passant par les fonctions de la CMDIChildWnd .
A partir de la fenêtre fille dans la fonction OnInitialUpdate() on commence par récupérer le pointeur sur la MDI avec la fonction GetParentFrame() pour appeler MDIActivate( );

Code c++ : Sélectionner tout
1
2
  
GetParentFrame()->MDIActivate( );

Mis à jour le 5 avril 2013 farscape

En passant par les fonctions de la CMDIChildWnd .
A partir de la fenêtre fille dans la fonction OnInitialUpdate() on commence par récupérer le pointeur sur la MDI avec la fonction GetParentFrame() pour appeler ActivateFrame:

Code c++ : Sélectionner tout
1
2
3
4
  
CFrameWnd::ActivateFrame 
virtual void ActivateFrame(  
int nCmdShow = - 1);
le paramètre nCmdShow correspond à la fonction ShowWindow.

Code c++ : Sélectionner tout
1
2
  
GetParentFrame()->ActivateFrame(SW_RESTORE);
Cette fonction modifie le z order des fenêtres en faisant passer la fenêtre en avant plan.

Mis à jour le 5 avril 2013 farscape

On rajoutera la séquence SetWindowPos dans la fonction OnCreate de la classe CMainFrame juste après les initialisations classiques toolbar dialogbar etc...

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
  
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{ 
    if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) 
    return -1; 
    if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP 
            | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || 
            !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) 
    { 
        TRACE0("Failed to create toolbar\n"); 
        return -1;      // fail to create 
    } 
    if (!m_wndStatusBar.Create(this) || 
        !m_wndStatusBar.SetIndicators(indicators, 
        sizeof(indicators)/sizeof(UINT))) 
    { 
  
        TRACE0("Failed to create status bar\n"); 
        return -1;      // fail to create 
    } 
  
    // TODO: Delete these three lines if you don't want the toolbar to 
    //  be dockable 
    m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); 
    EnableDocking(CBRS_ALIGN_ANY); 
    DockControlBar(&m_wndToolBar); 
  
    // MainFrame Always on Top !  
    CRect rect; 
    GetWindowRect( rect ); 
    ::SetWindowPos(m_hWnd , 
                    HWND_TOPMOST, 
                    rect.left,      
                    rect.top,        
                    rect.Width(),    
                    rect.Height(),  
                    SWP_SHOWWINDOW);  
  
    return 0; 
}

Mis à jour le 5 avril 2013 farscape

Code c++ : Sélectionner tout
1
2
3
4
5
6
  
CRect  RectFrame; 
// Récupération de la taille de la mdi 
GetParentFrame()->GetWindowRect(&RectFrame); 
// changement de la hauteur sans bouger la fenêtre . 
GetParentFrame()->SetWindowPos(NULL,0,0,RectFrame.Width(),lParam,SWP_NOMOVE | SWP_NOZORDER);
où lParam représente ici ma nouvelle hauteur.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
  
BOOL SetWindowPos (  
const CWnd* pWndInsertAfter,  
int x,  
int y,  
int cx,  
int cy,  
UINT nFlags );

Mis à jour le 5 avril 2013 farscape

Dans une application MFC il n' y a pas de mécanismes standard pour la mémorisation des fenêtres.
Pour remédier à ce problème il faudra mettre en place une sauvegarde de la position et taille de la fenêtre principale (MainFrame) et des fenêtres Filles (MDIChild).

Le code qui suit est une implémentation de ces fonctionnalités avec une classe template permettant l'insertion dans un projet existant sans modifications excessives de code :

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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// TplMDIFrame.hpp : interface of the CTplMDIFrame class 
// 
///////////////////////////////////////////////////////////////////////////// 
#if !defined(AFX_TPLMDIFRAME_H__59DC7C67_79D6_4082_A38B_4CD17E8257C1__INCLUDED_) 
#define AFX_TPLMDIFRAME_H__59DC7C67_79D6_4082_A38B_4CD17E8257C1__INCLUDED_ 
  
#if _MSC_VER > 1000 
#pragma once 
#endif // _MSC_VER > 1000 
// Farscape : le 22/02/2005 Beta 1.0 
  
// classe de base et traitement sur la MainFrame. 
template <class GENERIC_FRAME> 
class CTplMDIFrame : public GENERIC_FRAME 
{ 
public: 
    CTplMDIFrame() 
    { 
        m_rectFrame=CRect(0,0,0,0); 
        m_bMaximized=FALSE; 
        m_bInitPos=false; 
  
        SetSectionName(); 
    } 
    //------------------------ 
    virtual ~CTplMDIFrame(){SaveFramePos();} 
    void SetSectionName(const char *szSection="AppPos") 
    { 
        m_strSection=szSection; 
    } 
    //------------------------ 
    void    SaveFramePos() 
    { 
        MakeSection(); 
        AfxGetApp()->WriteProfileInt(m_strSection, "Maximized", m_bMaximized); 
        AfxGetApp()->WriteProfileBinary(m_strSection, "FrameRect", (BYTE*)&m_rectFrame,sizeof(CRect)); 
        AfxGetApp()->WriteProfileBinary(m_strSection, "InitialFrameRect", (BYTE*)&m_rectInitialFrame,sizeof(CRect)); 
    } 
    //------------------------ 
    virtual void MakeSection(){} 
    //------------------------ 
    voidLoadFramePos() 
    { 
        BYTE* pb = NULL; 
        UINT nLen = 0;         
        MakeSection(); 
        m_bMaximized = AfxGetApp()->GetProfileInt(m_strSection, "Maximized", (int)FALSE);         
        m_rectFrame.SetRect(0,0,0,0);         
        m_rectInitialFrame.SetRect(0,0,0,0); 
        if (AfxGetApp()->GetProfileBinary(m_strSection, "FrameRect", &pb, &nLen)) 
        { 
            ASSERT(nLen == sizeof(CRect)); 
            memcpy(&m_rectFrame, pb, sizeof(CRect)); 
            delete pb; 
        }         
        if (AfxGetApp()->GetProfileBinary(m_strSection, "InitialFrameRect", &pb, &nLen)) 
        { 
            ASSERT(nLen == sizeof(CRect)); 
            memcpy(&m_rectInitialFrame, pb, sizeof(CRect)); 
            delete pb; 
        }         
  
        CRect rectScreen(0, 0, GetSystemMetrics(SM_CXSCREEN),  
            GetSystemMetrics(SM_CYSCREEN)); 
        CRect rectInt; 
        rectInt.IntersectRect(&rectScreen, &m_rectFrame); 
        if (rectInt.Width() < 10 || rectInt.Height() < 10) m_rectFrame.SetRect(0, 0, 0, 0); 
    } 
    //------------------------ 
    voidShowMainFrame(int nCmdShow) 
    { 
        ASSERT(this->IsKindOf( RUNTIME_CLASS(CMDIFrameWnd))); 
  
        AfxGetApp()->m_nCmdShow =nCmdShow; 
        if (m_bMaximized) AfxGetApp()->m_nCmdShow = SW_SHOWMAXIMIZED; 
        ShowWindow(AfxGetApp()->m_nCmdShow); 
        UpdateWindow(); 
    } 
    //------------------------ 
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs) 
    { 
        if(cs.lpszClass && !m_bInitPos)  
        { 
            LoadFramePos(); 
            m_bInitPos=true; 
            if(m_rectFrame.Width() > 0 && m_rectFrame.Height() > 0) 
            { 
                cs.x  = m_rectFrame.left; 
                cs.y  = m_rectFrame.top; 
                cs.cx = m_rectFrame.Width(); 
                cs.cy = m_rectFrame.Height(); 
            } 
        } 
        // MainFrame 
        if(this->IsKindOf( RUNTIME_CLASS(CMDIFrameWnd))) 
        { 
            if(!GENERIC_FRAME::PreCreateWindow(cs) ) return FALSE; 
        } 
        else 
        {         
            // child 
            if(GENERIC_FRAME::PreCreateWindow(cs) ) return FALSE; 
        } 
        // TODO: Modify the Window class or styles here by modifying 
        //  the CREATESTRUCT cs         
  
        return TRUE; 
    }     
    // --------------------------- 
  
    CRect &GetInitialRectFrame(){return m_rectInitialFrame;} 
    // --------------------------- 
    void  SetInitialRectFrame(CRect Rect){m_rectInitialFrame=Rect;} 
    // --------------------------- 
    void GetWndPos() 
    { 
        WINDOWPLACEMENT wp; 
        wp.length = sizeof(wp); 
        GetWindowPlacement(&wp); 
        m_rectFrame = wp.rcNormalPosition; 
  
    } 
    //------------------------ 
    virtual LRESULT DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam) 
    {         
        if(nMsg==WM_DESTROY ) 
        { 
            m_bMaximized = (GetStyle() & WS_MAXIMIZE); 
            GetWndPos(); 
        } 
        if(nMsg==WM_MOVE) 
        { 
            GetWndPos(); 
        } 
        if(nMsg==WM_SIZE) 
        { 
            GetWndPos();             
        } 
        return GENERIC_FRAME::DefWindowProc( nMsg, wParam,lParam); 
    }      
  
    // Attributes 
public: 
    bool    m_bInitPos;             
    BOOL    m_bMaximized; 
    CRect   m_rectFrame; 
    CRect   m_rectInitialFrame; 
    CString m_strSection; 
}; 
// classe pour les MDIChild. 
class CMDIChildEx : public CTplMDIFrame<CMDIChildWnd> 
{     
public: 
    CMDIChildEx() 
    { 
        m_nPosCurrent=-1; 
        SetSectionName("Child");   
    } 
    ~CMDIChildEx() 
    { 
        POSITION pos=m_ListSection.Find(m_strSection); 
        if(pos)      m_ListSection.RemoveAt(pos);         
    } 
    //------------------------ 
    virtual void ActivateFrame( int nCmdShow = -1 ) 
    { 
        if(m_bMaximized ) nCmdShow = SW_MAXIMIZE; 
        CMDIChildWnd::ActivateFrame(nCmdShow); 
    }    
    virtual void MakeSection() 
    { 
        CString str; 
        str.Format("%s-%d",(const char *)m_strSection,m_nIDHelp); 
        m_strSection=str; 
  
        if(m_nPosCurrent==-1) 
        { 
            int i=0; 
            while(1) 
            { 
                str.Format("%s:%d",(char *)(const char *)m_strSection,i); 
                if(m_ListSection.Find(str)) i++; 
                else 
                { 
                    m_ListSection.AddTail(str);             
                    break; 
                } 
            } 
            m_nPosCurrent=i; 
        }         
        m_strSection=str; 
    } 
public: 
    static CList<CString ,CString&> m_ListSection; 
protected: 
    int m_nPosCurrent; 
  
}; 
#endif // !defined(AFX_TPLMDIFRAME_H__59DC7C67_79D6_4082_A38B_4CD17E8257C1__INCLUDED_) 
// TplMDIFrame.cpp 
#include "stdafx.h" 
#include "TplMDIFrame.hpp" 
  
CList<CString ,CString&> CMDIChildEx::m_ListSection;

Utilisation: au niveau de la classe CMainframe:

Code C++ : Sélectionner tout
1
2
3
4
5
#include "TplMDIFrame.hpp" 
  
class CMainFrame : public CTplMDIFrame<CMDIFrameWnd> 
{ 
    ..........

au niveau de la classe CChildFrame

Code C++ : Sélectionner tout
1
2
3
4
#include "TplMDIFrame.hpp" 
class CChildFrame : public CMDIChildEx 
{ 
    ........

au niveau de la classe d'application dans la fonction initInstance :

Code C++ : Sélectionner tout
1
2
3
4
5
// The main window has been initialized, so show and update it. 
    pMainFrame->ShowMainFrame(m_nCmdShow); 
// la ligne du dessous remplace ces deux lignes 
//pMainFrame->ShowWindow(m_nCmdShow); 
//pMainFrame->UpdateWindow();

au niveau des View il faudra enlever la ligne ResizeParentToFit():

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
void CTestMdILayoutView::OnInitialUpdate() 
{ 
    CFormView::OnInitialUpdate(); 
  
    // ne pas appeler  
    //ResizeParentToFit(); 
}

Fonctionnalités : Ces classes template permettent la gestion de la taille et position de la fenêtre principale ainsi que le mode maximiser de l'application.
Au niveau des fenêtres filles, on retrouve les mêmes fonctionnalités plus la gestion des positions pour plusieurs fenêtres de la même classe.
La différenciations des views se fait grâce à leur numéro d'identifiant dans les ressources.

Ces informations sont stockées dans le .ini de l'application qui ressemblera à ça :

Code ini : Sélectionner tout
1
2
3
4
5
6
7
8
9
[AppPos] 
Maximized=16777216 
FrameRect=EIAAAAAAOKAAAAAAEIDAAAAAHNCAAAAA 
[Child-129:0] 
Maximized=0 
FrameRect=HMBAAAAAHABAAAAAKPDAAAAACKCAAAAA 
[Child-129:1] 
Maximized=0 
FrameRect=PPPPPPPPPPPPPPPPNMBAAAAAFABAAAAA

L'application est référencée par AppPos et les fenêtres filles par Child suivi du numéro d'identifiant et le numéro d'appel.

Un exemple complet : TestMdiLayout.zip

Mis à jour le 19 septembre 2005 farscape

Dans un contexte SDI/MDI, le titre d'une fenêtre est régi par le document auquel elle se rattache. Ce comportement est dû au style FWS_ADDTOTITLE, activé par défaut, du cadre affichant la vue.

Le nom du document est demandé à la création du projet. A l'étape 4 de l'AppWizard, cliquez sur "Advanced..." :

  • le champ "Main frame caption" détermine le début du titre du cadre principal
  • le champ "Doc type name" détermine la racine du nom par défaut du document. Si on ne met rien la racine sera "sans nom".

le nom du document peut aussi être modifié dans le code par l'appel de la fonction CDocument::SetTitle(LPCTSTR lpszTitle).

Le titre sera formaté ainsi :

- SDI : pour le cadre principal : "nom par défaut du document - nom du cadre"

- MDI :
pour le cadre principal :

  • sans document ouvert : "titre cadre principal"
  • avec document ouvert : "titre cadre principal - racine du nom du document actif et n°"
  • avec document ouvert et vue maximisée : "titre cadre principal - [racine du nom du document actif et n°]" pour une vue : "racine du nom du document actif et n°"

On peut vouloir modifier ce mécanisme pour personnaliser le titre d'une vue. Cela peut-être intéressant dans un contexte SDI ou MDI à document à vues multiples. Pour cela, chaque vue doit être associée à une ressource IDR (menu, icône, ...) différente (ce qui donnera lieu à une chaîne par ressource dans la String Table).

1. On modifie la chaîne de la String Table associée à chaque ressource ( Comment changer le filtre de l'ouverture de fichiers dans une application MFC ?) :

SDI

Code c++ : Sélectionner tout
1
2
3
4
5
ID              Value    Caption 
IDR_MAINFRAME   128      Titre main frame\nRacine nom doc par défaut\n\nFichier machin (*.m)\n.m\nM.Document\nM Document 
IDR_TATA        129      Titre perso de la 1ère vue\n\n\n\n\n\n 
IDR_TITI        130      Titre perso de la 2ème vue\n\n\n\n\n\n 
IDR_TOTO        131      Titre perso de la 3ème vue\n\n\n\n\n\n
MDI

Code c++ : Sélectionner tout
1
2
3
4
5
ID              Value    Caption 
IDR_MAINFRAME   128      Titre main frame\n\nRacine nom doc par défaut\nFichier machin (*.m)\n.m\nM.Document\nM Document 
IDR_TATA        129      Titre perso de la 1ère vue\n\n\n\n\n\n 
IDR_TITI        130      Titre perso de la 2ème vue\n\n\n\n\n\n 
IDR_TOTO        131      Titre perso de la 3ème vue\n\n\n\n\n\n
2. Surcharger la fonction CWnd:reCreateWindow :

SDI
On surchargera CMainFrame:reCreateWindow(CREATESTRUCT& cs).

MDI

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs) 
{ 
    // le titre de la fenêtre ne correspond plus au titre du document 
    // si la ressource ne définit pas le champ titre, la fenêtre aura 
    // comme titre "sans nom" 
    cs.style &= ~(LONG)FWS_ADDTOTITLE; 
  
    // Appelle la fonction de la classe mère 
    return CMDIChildWnd::PreCreateWindow(cs); 
}

Mis à jour le 27 novembre 2005 bigboomshakala

Pour empêcher la fermeture d'une fenêtre il faut intercepter la commande SC_CLOSE comme dans Comment intercepter la fermeture de l'application ?
Pour griser l'option fermeture du menu système et griser la croix de la fenêtre on procédera comme suit :

Code C++ : Sélectionner tout
1
2
3
4
5
// exemple à partir de la view. 
CMenu *pSysMenu =GetParentFrame()->GetSystemMenu(FALSE); 
ASSERT(pSysMenu != NULL); 
  
pSysMenu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND  |MF_GRAYED   );

On commence par récupérer le menu système de la MDI, ensuite on règle le statut grisé avec la fonction EnableMenuItem pour l'identifiant SC_CLOSE.

Mis à jour le 20 mai 2006 farscape

Il faut intercepter le message WM_WINDOWPOSCHANGING sur la MDIChild. Exemple:

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
  
void CChildFrame::OnWindowPosChanging(WINDOWPOS* lpwndpos)  
{  
   if(!m_rect.IsRectEmpty())   // empeche de bouger...  
   {  
      lpwndpos->x=m_rect.left;  
      lpwndpos->y=m_rect.top;     
      CRect rectBarPos;  
      static_cast<CMainFrame *>(AfxGetMainWnd())->m_wndToolBar.GetWindowRect(&rectBarPos);  
      lpwndpos->y-=rectBarPos.Height();  
  
   }  
   CMDIChildWnd::OnWindowPosChanging(lpwndpos);  
  
   // TODO: Add your message handler code here  
} 
//------------------------------------------------------------  
void CChildFrame::OnSize(UINT nType, int cx, int cy)  
{  
   CMDIChildWnd::OnSize(nType, cx, cy);  
   if(m_rect.IsRectEmpty()) // position initiale  
   {  
      GetWindowRect(&m_rect);  
      AfxGetMainWnd()->ScreenToClient(&m_rect);  
   }  
   // TODO: Add your message handler code here  
}
Essai réalisé avec Visual 2005.
Il se peut que le message ne soit pas implémenté avec VC 6.
Il faudra le rajouter manuellement

Mis à jour le 20 mai 2006 farscape

Le cas typique est l'accès de la vue à partir d'une boîte de dialogue.

On pourra procéder comme suit :

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BOOL CMyDialog::OnInitDialog()  
{ 
    CDialog::OnInitDialog(); 
  
    // TODO: Add extra initialization here 
  
    // acces à la seule vue active  
    CView *pView=static_cast<CFrameWnd *>(AfxGetMainWnd())->GetActiveView(); 
    // transformation sur la classe de la vue. 
    CSampleSDIView * pSDIView= static_cast<CSampleSDIView *>(pView); 
  
    pSDIView->m_Edit.SetWindowText("essai"); 
    return TRUE;  // return TRUE unless you set the focus to a control 
                  // EXCEPTION: OCX Property Pages should return FALSE 
}

Pourquoi ne pas faire GetParent() ? Hé bien dans un projet SDI GetParent() dans la boîte de dialogue renvoie le pointeur sur la CMainFrame.
Voir aussi Comment récupérer la fenêtre parent dans une boîte de dialogue ?

Note : la méthode pourra aussi être appliquée sur un projet MDI.

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 © 2024 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.