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


SommaireClasses Fenêtres et FrameWorkGestion du framework (25)
précédent sommaire suivant
 

Il faut laisser à l'application le temps de traiter les messages sinon dés que l'on bouge la fenêtre ou si elle recouverte par une autre application il n'y a plus de reconstruction possible .
Solution intégrer dans sa boucle l'appel de la fonction suivante qui pourrait être une fonction static de la classe d'application par exemple :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  
/*static */void CMyApp ::PumpMessages()  
{  
   // Handle dialog messages  
    MSG msg;  
    while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))  
    {  
        if (!AfxGetApp()->PreTranslateMessage(&msg))  
      {  
         ::TranslateMessage(&msg);  
         ::DispatchMessage(&msg);  
     }             
     AfxGetApp()->OnIdle(0);   // updates user interface  
    AfxGetApp()->OnIdle(1);   // frees temporary objects  
    }  
}

Mis à jour le 5 avril 2013 farscape

Code c++ : Sélectionner tout
1
2
  
((CMDIFrameWnd *)AfxGetMainWnd())->GetActiveFrame( )->GetActiveView();
Récupération de la mainFrame ,puis de la MDI Active .
Et enfin de la view dans la MDI active.
Le test doit être découpé pour éviter un problème si il n'y a pas MDI active !

Code c++ : Sélectionner tout
1
2
  
CView* CFrameWnd::GetActiveView( ) const;

Mis à jour le 5 avril 2013 farscape

La réponse s'appuie sur les Q/R de la faq :



La fonction ci-dessous cherche une instance d'une classe fenêtre en l'identifiant par sa signature.

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
  
CWnd *FindInstanceView(CRuntimeClass *pViewClass) 
{ 
    CWinApp* pApp = AfxGetApp();         
    // parcourir tous les templates 
    CDocTemplate* pTemplate; 
    POSITION pos = pApp->GetFirstDocTemplatePosition(); 
    while (pos != NULL) 
    { 
        pTemplate = pApp->GetNextDocTemplate(pos); 
        ASSERT(pTemplate); 
  
        // tous les documents du template. 
        POSITION pos2 = pTemplate->GetFirstDocPosition(); 
        while (pos2) 
        { 
            CDocument* pDoc = pTemplate->GetNextDoc(pos2); 
            ASSERT(pDoc); 
  
            // toutes les vues du document 
            POSITION pos3 = pDoc->GetFirstViewPosition(); 
            while (pos3 != NULL) 
            { 
                CView* pView = pDoc->GetNextView(pos3); 
                ASSERT(pView); 
                if (::IsWindow(pView->GetSafeHwnd())) 
                { 
                    if(pView->IsKindOf(pViewClass)) 
                    { 
                        return pView; 
                    }                     
                } 
            } 
        } 
    } 
    return NULL; 
}
Utilisation: recherche d'une instance de la classe CTestMdiView .
si la fenêtre est trouvée on la refait passer en avant plan.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
  
CTestMdiView *pView; 
if((pView=static_cast<CTestMdiView *>(FindClassView(RUNTIME_CLASS(CTestMdiView))))) 
{ 
TRACE("\nInstance de la classe trouvée"); 
static_cast<CMDIChildWnd *>(pView->GetParentFrame())->ActivateFrame(SW_RESTORE); 
}

Mis à jour le 20 mai 2006 farscape

A chaque nIDResource associée à un document template on trouve dans l'éditeur de ressources dans la « stringtable » la chaîne d'ouverture pour le document.

Exemple:
Pour l'id IDR_TESTMDTYPE on pourra avoir :

Code c++ : Sélectionner tout
1
2
  
\nExts\nExts\nFichiers (*.txt)\n.txt\nExts.Doc\nExts Doc
Description :

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
  
IDR_TESTMDTYPE <windowTitle>\n<docName>\n<fileNewName>\n 
                    <filterName>\n <filterExt>\n<regFileTypeID>\n 
                    <regFileTypeName>\n <filterMacExt(filterWinExt)>\n 
                    <filterMacName(filterWinName)> 
  
IDR_TESTMDTYPE \nExts\nExts\nFichiers (*.txt ;*.doc)\n.txt; 
                                  .doc\Exts.Document.1\nExts Document\nExts\nExts Fichiers 
  
      <windowTitle>           Exts 
      <docName>              Exts 
      <fileNewName>        Exts 
      <filterName>             Fichiers (*.txt) 
      <filterExt>                  . txt 
      <regFileTypeId>        Exts.Document.1 
      <regFileTypeName>  Exts Document 
      <filterMacExt>           Exts 
      <filterMacName>      Exts Fichiers 
  
 <item> voir Note MSDN:</item> 
<b>INFO: Format of the Document Template String 
Q129095 
</b>
Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
  
CMultiDocTemplate* pDocTemplate; 
pDocTemplate = new CMultiDocTemplate( 
IDR_TESTMDTYPE, 
RUNTIME_CLASS(CTestMdiDoc), 
RUNTIME_CLASS(CChildFrame), // custom MDI child frame 
RUNTIME_CLASS(CTestMdiView)); 
AddDocTemplate(pDocTemplate);
A l'ouverture j'aurai bien : Fichiers *.txt
Pour gérer le multi documents à l'ouverture c'est plus compliqué
voir note MSDN:

Code c++ : Sélectionner tout
1
2
3
  
<b>HOWTO: How to Support Two File Extensions per MFC Document Type 
Q141921</b>

Mis à jour le 5 avril 2013 farscape

Dans un projet classique on a besoin de l'objet CMultiDocTemplate pour créer les fenêtres avec la commande suivante :

Code c++ : Sélectionner tout
1
2
3
  
// CMultiDocTemplate * m_pTplEditView; dans le header. 
m_pTplEditView->OpenDocumentFile(NULL) ;
Comment faire pour éviter la déclaration de données membres dans la classe d'application ?
Je propose la solution suivante :

  • Redéfinir une classe dérivée de CMultiDocTemplate.
  • Déclarer une fonction d'ouverture d'une fenêtre en fonction de la signature de la classe fenêtre (runtime).

La création pourra s'écrire de la manière suivante:

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
  
// CTestMdiApp message handlers 
void CTestMdiApp::OnFileNew()  
{ 
      // TODO: Add your command handler code here 
       OpenDocumentFile(RUNTIME_CLASS(CTestMdiView)); 
}
A la place de :

Code c++ : Sélectionner tout
1
2
3
4
5
6
  
void CTestMdiApp::OnFileNew()  
{ 
      // TODO: Add your command handler code here 
       m_pTplEditView->OpenDocumentFile(NULL) ; 
}
Implémentation:

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
  
// header 
class CExMultiDocTemplate : public CMultiDocTemplate 
{ 
    DECLARE_DYNAMIC(CExMultiDocTemplate) 
    // Constructors 
public: 
   CExMultiDocTemplate(UINT nIDResource, 
                       CRuntimeClass* pDocClass, 
                       CRuntimeClass* pFrameClass, 
                       CRuntimeClass* pViewClass): 
   CMultiDocTemplate(nIDResource,pDocClass,pFrameClass,pViewClass){} 
  
   CRuntimeClass* GetDocClass()   {return m_pDocClass;} 
   CRuntimeClass* GetFrameClass() {return m_pFrameClass;} 
   CRuntimeClass* GetViewClass()  {return m_pViewClass;} 
   UINT GetnIDResource()          {return m_nIDResource;} 
}; 
  
// .cpp 
IMPLEMENT_DYNAMIC(CExMultiDocTemplate,CMultiDocTemplate) 
CDocument *CTestMdiApp::OpenDocumentFile(CRuntimeClass *pClassView, 
                                         LPCTSTR lpszPathName/*=NULL*/,  
                                         BOOL bMakeVisible /*= TRUE*/ ) 
{ 
    // parcourir tous les templates 
    CDocTemplate* pTemplate; 
    POSITION pos = GetFirstDocTemplatePosition(); 
    while (pos != NULL) 
    { 
        pTemplate = GetNextDocTemplate(pos); 
        ASSERT(pTemplate); 
        if(pTemplate->IsKindOf(RUNTIME_CLASS(CExMultiDocTemplate))) 
        { 
            if(((CExMultiDocTemplate *)pTemplate)->GetViewClass()==pClassView) 
                 return pTemplate->OpenDocumentFile(lpszPathName,bMakeVisible); 
        } 
    } 
    return NULL; 
}
utilisation :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  
CExMultiDocTemplate *pTemplate; 
pTemplate = new CExMultiDocTemplate( 
IDR_TESTMDTYPE, 
RUNTIME_CLASS(CTestMdiDoc), 
RUNTIME_CLASS(CChildFrame), // custom MDI child frame 
RUNTIME_CLASS(CTestMdiView)); 
AddDocTemplate(pTemplate); 
  
pTemplate= new CExMultiDocTemplate( 
                            IDR_TESTMDTYPE, 
                            RUNTIME_CLASS(CTestMdiDoc), 
                            RUNTIME_CLASS(CChildFrame), // custom MDI child frame 
                            RUNTIME_CLASS(CEditView)); 
AddDocTemplate(pTemplate);
La classe CExMultiDocTemplate permet l'accès aux données membres de la classe de base, dans notre cas c'est le runtime de la classe fenêtre qui nous intéresse.
La fonction OpenDocumentFile parcourt tous les documents templates et recherche celui qui dispose de la signature fenêtre désirée pour appeler ensuite OpendocumentFile.
Donc plus besoin de variables pour stocker les documents templates et un appel simplifié par signature de classe pour créer la fenêtre.

Mis à jour le 5 avril 2013 farscape

En interceptant le message WM_GETMINMAXINFO.
Et en consultant les données de la structure MINMAXINFO,
Exemple limitation de la taille minimum de l'application à 320 pixels de large et 240 de haut.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
  
void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)  
{  
   // TODO: Add your message handler code here and/or call default             
    lpMMI->ptMinTrackSize.x = 320;  
    lpMMI->ptMinTrackSize.y = 240;                  
    CMDIFrameWnd::OnGetMinMaxInfo(lpMMI);  
}

Mis à jour le 5 avril 2013 farscape

En utilisant la fonction SetCursorPos.

Code c++ : Sélectionner tout
1
2
3
4
5
  
BOOL SetCursorPos( 
  int X,  // horizontal position 
  int Y   // vertical position 
);
Exemple en modifiant la position de la souris lors de son déplacement à la réception du message WM_MOUSEMOVE.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  
void CTestMdiView::OnMouseMove(UINT nFlags, CPoint point) 
{ 
   // TODO: Add your message handler code here and/or call default 
  
   if(!m_bMouseSetPos) // pour éviter la réentrance dans le message ! 
   {       
      CPoint pt=point; 
      pt.x = 100;          // fixer x a 100 pixels coté client  
      ClientToScreen(&pt); // conversion en coordonnées fenêtre 
      ::SetCursorPos(pt.x,pt.y); // fixe la position de la souris 
      m_bMouseSetPos=true;    // initialise le flag  
   } 
   else m_bMouseSetPos=false; // reset du flag  
  
   CFormView::OnMouseMove(nFlags, point); 
} 
m_bMouseSetPos=false; // à initialiser dans le constructeur.

Mis à jour le 5 avril 2013 farscape

Lorsqu'on a défini plusieurs objets de la classe CMultiDocTemplate dans InitInstance à l'appel la commande ID_FILE_NEW une fenêtre apparaît avec la liste des différents noms de documents disponibles.
Pour éviter cela il suffit de redéfinir la commande ID_FILE_NEW de la classe d'application et d'appeler l'ouverture de la fenêtre qui nous convient :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  
BEGIN_MESSAGE_MAP(CTestMdiApp, CWinApp) 
//{{AFX_MSG_MAP(CTestMdiApp) 
ON_COMMAND(ID_APP_ABOUT, OnAppAbout) 
ON_COMMAND(ID_FILE_NEW, OnFileNew) // redéfinition par classWizard 
//}}AFX_MSG_MAP 
// Standard file based document commands 
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) 
// Standard print setup command 
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup) 
END_MESSAGE_MAP() 
  
// CTestMdiApp message handlers 
void CTestMdiApp::OnFileNew()  
{ 
    // TODO: Add your command handler code here 
    m_pTplEditView->OpenDocumentFile(NULL) ; 
}

Mis à jour le 5 avril 2013 farscape

Il suffira de mettre en commentaire la séquence suivante contenue dans la fonction InitInstance de la classe d'application :

Code c++ : Sélectionner tout
1
2
3
4
5
  
//CCommandLineInfo cmdInfo; 
//ParseCommandLine(cmdInfo); 
// Dispatch commands specified on the command line 
//if (!ProcessShellCommand(cmdInfo)) return FALSE;

Mis à jour le 5 avril 2013 farscape

Dans une application MFC la gestion des documents lecture sauvegarde etc.. est prise en charge par un objet dérivé de la classe CDocument pour le document template concerné (voir CDocTemplate ).
Il suffira donc d'intercepter le message ID_FILE_SAVE sur la classe document par l'intermédiaire de « ClassWizard »
Si d'aventure on souhaitait l'intercepter au niveau de la mainframe on récupérera la notification avec la fonction OnCommand :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
  
BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)  
{ 
    // TODO: Add your specialized code here and/or call the base class 
    if(LOWORD(wParam)==ID_FILE_SAVE) 
    { 
        AfxMessageBox("Msg:ID_FILE_SAVE"); 
    } 
    return CMDIFrameWnd::OnCommand(wParam, lParam); 
}
Attention tout de même de savoir quel est le document concerné dans un contexte MDI.
Avec par exemple la fonction GetActiveDocument() :

Code c++ : Sélectionner tout
1
2
3
  
CFrameWnd::GetActiveDocument 
virtual CDocument* GetActiveDocument( );

Mis à jour le 7 juillet 2008 farscape

En simulant l'appel des commandes : ID_VIEW_TOOLBAR et ID_VIEW_STATUS_BAR comme sur le menu standard: "affichage" de l'application.
A partir de la view on récupère le pointeur sur la mainframe, puis on désactive la toolbar et la statusbar par l'envoi d'un message WM_COMMAND.
Les mêmes appels feront réapparaître les barres comme dans le menu...

Code c++ : Sélectionner tout
1
2
3
4
5
  
// dans la view sur l'appel d'un bouton par exemple. 
CMainFrame * pMain=(CMainFrame *)AfxGetMainWnd(); 
pMain->SendMessage(WM_COMMAND, ID_VIEW_TOOLBAR, 0L); 
pMain->SendMessage(WM_COMMAND, ID_VIEW_STATUS_BAR,0L);

Mis à jour le 5 avril 2013 farscape

Dans le cas d'un projet SDI il faut faire le travail sur la mainframe.
Exemple sur l'action d'un bouton situé dans une CFormView:

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
  
void CTestSDIView::OnButton1() 
{ 
   // TODO: Add your control notification handler code here 
    // Récupération de la taille de la mainframe 
    CRect  RectFrame; 
    AfxGetMainWnd()->GetWindowRect(&RectFrame); 
    // changement de taille +100 en hauteur et largeur. 
    AfxGetMainWnd()->SetWindowPos(NULL,0,0, 
                                       RectFrame.Width()+100, 
                                       RectFrame.Height()+100, 
                                       SWP_NOMOVE | SWP_NOZORDER); 
}

Mis à jour le 5 avril 2013 farscape

La technique utilisée est différente de celle de la boîte de dialogue, on fournit ici une fenêtre parent de style popup à la mainframe.

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
  
CMainFrame::~CMainFrame() 
{ 
    if (m_HideWnd.m_hWnd != NULL) m_HideWnd.DestroyWindow(); 
} 
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) 
{ 
    //CWnd m_HideWnd ; comme donnée membre de la classe CMainFrame. 
  
    if (!CFrameWnd::PreCreateWindow(cs)) 
    return FALSE; 
  
    if(m_HideWnd.m_hWnd==NULL) 
   { 
        if (!m_HideWnd.CreateEx(0, AfxRegisterWndClass(0), _T(""), WS_POPUP, 
       CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
       NULL, 0)) 
      return FALSE; 
   } 
   cs.hwndParent = m_HideWnd.m_hWnd; 
   return TRUE; 
}

Mis à jour le 5 avril 2013 farscape

Pour préciser le sujet:
Il arrive parfois que l'on ait besoin de créer dynamiquement des contrôles à l'initialisation de la CFormView ,
Dans ce contexte, il s'avère utile de connaître la surface disponible pour placer au mieux les contrôles.
L'endroit le plus approprié étant la fonction OnInitialUpdate .
Pour avoir un résultat correct avec la fonction GetClienRect, il faudra d'abord procéder à une demande de recalcule de la taille de la frame.

Code c++ : Sélectionner tout
1
2
3
4
5
  
GetParentFrame()->RecalcLayout();  
ResizeParentToFit();  
CRect Rect ; 
GetClientRect(&Rect) ;
ResizeParentToFit assure que la dimension de la vue soit bien réglée.
L'appel à RecalcLayout est indispensable avant ResizeParentToFit(risque d'assertion), il assure lors du dimensionnement de la frame le rafraîchissement des barres de contrôles.

Mis à jour le 5 avril 2013 farscape

En surchargeant la fonction membre virtuelle CWnd:reCreateWindow pour modifier la structure CREATESTRUCT, qui définit les paramètres d'initialisation de la fenêtre (i.e. du cadre), avant la création de celle-ci.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef struct tagCREATESTRUCT { 
    LPVOID lpCreateParams; 
    HINSTANCE hInstance; 
    HMENU hMenu; 
    HWND hwndParent; 
    int cy; 
    int cx; 
    int y; 
    int x; 
    LONG style; 
    LPCTSTR lpszName; 
    LPCTSTR lpszClass; 
    DWORD dwExStyle; 
} CREATESTRUCT, *LPCREATESTRUCT;
(cx,cy) : largeur et hauteur de la nouvelle fenêtre, en pixels
(x,y) : coordonnées du coin supérieur gauche de la fenêtre, en pixels.
style : style de la nouvelle fenêtre ( Available styles, Frame-window styles) dwExStyle : style étendu de la nouvelle fenêtre
Exemple pour un projet SDI :

Le style par défaut est une combinaison de WS_OVERLAPPEDWINDOW et FWS_ADDTOTITLE. FWS_ADDTOTITLE indique au framework d'ajouter au titre de la fenêtre le titre du document.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) 
{ 
    // Fenêtre sans boutons min/max et bords dimensionnables 
    cs.style = WS_OVERLAPPED | WS_SYSMENU | WS_BORDER; 
  
    // Dimensionne au 1/3 de la taille de l'écran la fenêtre, et la centre 
    cs.cy = ::GetSystemMetrics(SM_CYSCREEN) / 3; 
    cs.cx = ::GetSystemMetrics(SM_CXSCREEN) / 3; 
    cs.y = ((cs.cy * 3) - cs.cy) / 2; 
    cs.x = ((cs.cx * 3) - cs.cx) / 2; 
  
    // Appelle la fonction de la classe mère 
    return CFrameWnd::PreCreateWindow(cs); 
}
Exemple pour un projet MDI :

Le style par défaut est une combinaison de WS_CHILD, WS_OVERLAPPEDWINDOW et FWS_ADDTOTITLE.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs) 
{ 
    // Crée une fenêtre sans bouton Maximiser 
    cs.style &= ~WS_MAXIMIZEBOX; 
  
    // Appelle la fonction de la classe mère 
    return CMDIChildWnd::PreCreateWindow(cs); 
}

Mis à jour le 27 novembre 2005 bigboomshakala

Il y a bien une différence dans la fonction AfxGetMainWnd() à partir de VC7 et les versions précédentes..

Code c++ : Sélectionner tout
1
2
3
4
  
_AFXWIN_INLINE CWnd* AFXAPI AfxGetMainWnd() 
    { CWinThread* pThread = AfxGetThread(); 
        return pThread != NULL ? pThread->GetMainWnd() : NULL; }

Cette fonction appel la fonction AfxGetThread(), et cette fonction est implémentée différemment à partir de VC7...
en VC7 :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
  
CWinThread* AFXAPI AfxGetThread() 
{ 
  // check for current thread in module thread state 
  AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState(); 
  CWinThread* pThread = pState->m_pCurrentWinThread; 
  return pThread; 
}


En VC6.0 :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
  
CWinThread* AFXAPI AfxGetThread() 
{ 
  // check for current thread in module thread state 
  AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState(); 
  CWinThread* pThread = pState->m_pCurrentWinThread; 
  //if no CWinThread for the module, then use the global app 
  if (pThread == NULL) 
      pThread = AfxGetApp(); 
  return pThread; 
}

donc on peux remplacer notre appel de AfxGetMainWnd() par :

Code c++ : Sélectionner tout
1
2
  
AfxGetApp()->GetMainWnd();


pourquoi ce code a été modifié reste un mystère ...

Mis à jour le 22 janvier 2007 farscape

Pour empêcher dans un contexte MDI de déplacer une fenêtre fille dans la surface de travail de l'application on interceptera 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 
}
Sur le premier WM_SIZE de la fenêtre on mémorise sa position et sur le message WM_WINDOWPOSCHANGING on la restitue.

Mis à jour le 17 septembre 2007 farscape

L'espace de travaille alloué à la mainframe dans le mode maximisé dépend directement de la résolution de l'écran,
Pour disposer d'une surface plus grande on rajoutera les styles WS_VSCROLL | WS_HSCROLL à la création de la MainFrame.
Dés qu'une fenêtre sera poussée ou créer en dehors de la surface normale d'affichage, les ascenseurs apparaitront agrandissant du même coup notre espace de travail.

Comment procéder :
Surchargez avec l'assistant la fonction virtuelle PreCreateWindows et rajouter les styles pour les barres d'ascenseurs.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
  
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) 
{ 
    // TODO: Modify the Window class or styles here by modifying 
    //  the CREATESTRUCT cs     
    cs.style |=(WS_VSCROLL | WS_HSCROLL);     
    return CMDIFrameWnd::PreCreateWindow(cs); 
}

Mis à jour le 17 septembre 2007 farscape

On rajoutera le code suivant à la classe CMainFrame créée :

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
  
//CArray <CView *,CView *> m_arView; a déclarer comme variable membre de la classe. 
//----------------------------------------------- 
void CMainFrame::ActiveFormView(int n) 
{ 
	VERIFY(n<m_arView.GetCount()); 
  
	CView* pActiveView = GetActiveView(); 
	CView *pNewView = m_arView[n]; 
  
    UINT temp = ::GetWindowLong(pActiveView->m_hWnd, GWL_ID); 
    ::SetWindowLong(pActiveView->m_hWnd, GWL_ID, 
    ::GetWindowLong(pNewView->m_hWnd, GWL_ID)); 
    ::SetWindowLong(pNewView->m_hWnd, GWL_ID, temp); 
  
    pActiveView->ShowWindow(SW_HIDE); 
    pNewView->ShowWindow(SW_SHOW); 
    SetActiveView(pNewView); 
    RecalcLayout(); 
    pNewView->Invalidate(); 
} 
//----------------------------------------------- 
CView *CMainFrame::AddView(CRuntimeClass *pClassView) 
{ 
	CView* pView = static_cast<CView *>(pClassView->CreateObject()); 
	CView* pActiveView = GetActiveView(); 
  
	if(!m_arView.GetCount()) m_arView.Add(pActiveView); 
  
    CDocument* pCurrentDoc = GetActiveDocument(); 
  
    CCreateContext newContext; 
    newContext.m_pNewViewClass = NULL; 
    newContext.m_pNewDocTemplate = NULL; 
    newContext.m_pLastView = NULL; 
    newContext.m_pCurrentFrame = NULL; 
    newContext.m_pCurrentDoc = pCurrentDoc; 
  
    CRect rect(0, 0, 0, 0);  
    pView->Create(NULL, NULL,(AFX_WS_DEFAULT_VIEW & ~WS_VISIBLE),rect, this, 
				AFX_IDW_PANE_FIRST + m_arView.GetCount(), &newContext); 
	m_arView.Add(pView); 
	pView->OnInitialUpdate(); 
	return pView; 
}
J'ai implémenté deux méthodes :
Une pour la création de la vue d'après un Runtime de classe fourni, l'autre pour activer la vue.
La vue 0 est la vue principale. L'ensemble des vues est stocké dans un CArray.
Utilisation:
dans InitInstance je demande la création d'une vue:

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
  
  
	// La seule fenêtre a été initialisée et peut donc être affichée et mise à jour 
	m_pMainWnd->ShowWindow(SW_SHOW); 
	m_pMainWnd->UpdateWindow(); 
	// appelle DragAcceptFiles uniquement s'il y a un suffixe 
	//  Dans une application SDI, cet appel doit avoir lieu juste après ProcessShellCommand 
	static_cast<CMainFrame*>(m_pMainWnd)->AddView(RUNTIME_CLASS(CEditView));
Dans mon exemple j'ai ajouté une CEditView. Pour procéder à l'activation on appellera ActiveFormView:

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
  
void CMainFrame::OnFenetre1() 
{ 
	// TODO: Add your command handler code here 
	ActiveFormView(0); 
} 
void CMainFrame::OnFenetre2() 
{ 
	// TODO: Add your command handler code here 
	ActiveFormView(1); 
}

Mis à jour le 7 juillet 2008 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++