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
- 5.7.1. CSplitterWnd (6)
- Comment faire pour que dans une boucle de traitement l'application ne semble pas figée ?
- Comment récupérer le pointeur sur la fenêtre active ?
- Comment savoir s'il existe une instance d'une View en MDI ?
- Comment changer le filtre de l'ouverture de fichiers dans une application MFC ?
- Comment éviter le stockage d'objet CMultiDocTemplate pour l'appel des fenêtres dans un projet MDI ?
- Comment limiter la taille minimum d'une Application ?
- Comment intervenir sur le positionnement de la souris ?
- Comment éviter d'avoir la sélection de fenêtre à ouvrir sur la commande ID_FILE_NEW dans un projet MDI avec plusieurs fenêtres ?
- Comment éviter le lancement automatique d'une fenêtre au départ de l'application MDI ?
- Comment intercepter le message ID_FILE_SAVE ?
- Comment désactiver/activer la statusbar ou la toolbar ?
- Comment changer la taille d'une View dans un contexte SDI?
- Comment faire une application MDI/SDI sans bouton dans la barre des tâches Windows ?
- Comment récupérer la surface client d'une CFormView à son initialisation ?
- Comment personnaliser la création d'une Frame en SDI/MDI ?
- Pourquoi l'appel à AfxGetMainWnd peut provoquer une erreur avec Visual .Net ?
- Comment empêcher une fenêtre fille d'être déplacée dans la surface de travail de l'application?
- Comment avoir une surface de travail dynamique sur la MainFrame ?
- Comment créer dynamiquement une vue dans une application SDI ?
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 } } |
Code c++ : | Sélectionner tout |
1 2 | ((CMDIFrameWnd *)AfxGetMainWnd())->GetActiveFrame( )->GetActiveView(); |
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; |
La réponse s'appuie sur les Q/R de la FAQ :
- Comment parcourir dans un contexte MDI toutes les fenêtres de l'application ?
- Comment activer et faire passer en premier plan une fenêtre fille (Child)?
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 | 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 | 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); } |
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 |
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); |
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> |
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) ; |
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)); } |
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) ; } |
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; } |
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 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.
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); } |
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 ); |
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. |
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) ; } |
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; |
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); } |
Avec par exemple la fonction GetActiveDocument() :
Code c++ : | Sélectionner tout |
1 2 3 | CFrameWnd::GetActiveDocument virtual CDocument* GetActiveDocument( ); |
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); |
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); } |
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; } |
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) ; |
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.
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; |
(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); } |
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); } |
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 ...
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 } |
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); } |
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; } |
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)); |
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); } |
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 çaLes 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.