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
- Comment implanter des éléments dans une CStatusBar ?
- Comment ajouter une barre d'état dans un contexte SDI/MDI qui en est dépourvu ?
- Comment gérer les indicateurs dans la barre d'état ?
- Comment afficher/masquer une barre d'état personnalisée ?
- Comment intégrer une barre de progression dans la barre d'état ?
- Comment mettre un bitmap dans la barre d'états ?
Les traitements liés à la CStatusBar sont situés dans la classe de fenêtre principale CMainFrame.
Dans un projet classique on doit trouver un tableau initialisé avec les valeurs standard des indicateurs claviers :
ID_INDICATOR_CAPS : Majuscule/Minuscule
ID_INDICATOR_NUM, : Verrou Numérique
ID_INDICATOR_SCRL, :
Pour personnaliser ce tableau procédez comme suit :
Dans tous les cas la première ligne du tableau indicators doit comporter ID_SEPARATOR
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 | static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_1, ID_INDICATOR_2, ID_INDICATOR_3 }; |
Ajouter dans la String Table l'ID_INDICATOR_x que l'on vient de créer (on va le chercher dans la liste)
Ensuite dans l'entête mainframe.h rajouter la ligne
Code c++ : | Sélectionner tout |
1 2 | void OnUpdatePane (CCmdUI *pCmdUI) { pCmdUI->Enable (); |
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 | BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) // NOTE - the ClassWizard will add and remove mapping macros here. // DO NOT EDIT what you see in these blocks of generated code ! ON_WM_CREATE() //}}AFX_MSG_MAP ON_UPDATE_COMMAND_UI ( ID_INDICATOR_1, OnUpdatePane ) ON_UPDATE_COMMAND_UI ( ID_INDICATOR_2, OnUpdatePane ) ON_UPDATE_COMMAND_UI ( ID_INDICATOR_3, OnUpdatePane ) END_MESSAGE_MAP() // dans oncreate //................ // ********** Status Bar ************************************** m_wndStatusBar.SetPaneInfo(1, ID_INDICATOR_1, SBPS_NORMAL ,50); m_wndStatusBar.SetPaneInfo(2, ID_INDICATOR_2, SBPS_NORMAL,50); m_wndStatusBar.SetPaneInfo(3, ID_INDICATOR_3, SBPS_NORMAL,50); // affectation d'une valeur a un panneau m_wndStatusBar.SetPaneText(m_wndStatusBar.CommandToIndex(ID_INDICATOR_1), "Valeur 1"); |
Si vous avez décoché l'option "initial status bar" à l'étape 4 de la création de votre projet, alors vous n'aurez pas de barre d'état. Que faire si votre projet, déjà bien avancé, nécessite finalement la barre d'état ? La solution tient en quelques lignes.
1. Déclarer une donnée membre CStatusBar dans la classe CMainFrame
Code c++ : | Sélectionner tout |
1 2 | private: CStatusBar m_wndStatusBar; |
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 | static UINT indicators[] = { ID_SEPARATOR, ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; |
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 | if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators) / sizeof(UINT))) { TRACE0("Impossible de créer la barre d'état\n"); return -1; } |
La barre d'état par défaut est constituée d'un panneau de message (ID_SEPARATOR) et de trois panneaux d'indicateurs:
ID_INDICATOR_CAPS,ID_INDICATOR_NUM,ID_INDICATOR_SCRL.
Un panneau d'indicateur est lié à une unique chaîne de caractère, fournie par une ressource (String Table), affichée ou cachée suivant le gestionnaire d'actualisation de l'interface associée.
La dimension du panneau est égale à la largeur de la chaîne de caractères.
Si l'on veut par exemple afficher "Ctrl/Ret" si Control et Return sont pressés (en même temps ou séparément) :
1. On définit ID_IND_CTRL_RET dans la String Table, associé à la chaîne "Ctrl/Ret"
2.
Code c++ : | Sélectionner tout |
1 2 3 | // MainFrm.h public: void OnUpdateKeyReturn(CCmdUI* pCmdUI); |
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 | // MainFrm.cpp static UINT indicators[] = { ID_SEPARATOR, ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_IND_CTRL_RET, }; ... BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ... //}}AFX_MSG_MAP ON_UPDATE_COMMAND_UI(ID_INDICATOR_ENT,OnUpdateKeyReturn) END_MESSAGE_MAP() ... void CMainFrame::OnUpdateKeyReturn(CCmdUI* pCmdUI) { pCmdUI->Enable(::GetKeyState(VK_RETURN) & ::GetKeyState(VK_CONTROL) & 1); } |
Comme on a changé l'ID de la barre d'état pour gérer soi-même l'affichage, la commande Affichage/Barre d'état, gérée par l'architecture d'application, n'agit plus. On va donc devoir gérer soi-même la commande.
On déclare une variable booléenne dans la classe CMainFrame. Cet booléen indique si la barre d'état est visible ou non, et si un check doit apparaître devant la commande Affichage/Barre d'état :
Code c++ : | Sélectionner tout |
1 2 3 | //MainFrm.h private: bool m_bStatusBarIsVisible; |
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 | if (!m_wndStatusBar.Create(this,WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, ID_MY_STATUS_BAR) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators) / sizeof(UINT))) { TRACE0("Impossible de créer la barre d'état\n"); return -1; } m_bStatusBarIsVisible = (m_wndStatusBar.IsWindowVisible() == 0); |
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | void CMainFrame::OnViewStatusBar() { if(m_bStatusBarIsVisible) m_wndStatusBar.ShowWindow(SW_HIDE); else m_wndStatusBar.ShowWindow(SW_SHOW); RecalcLayout(); m_bStatusBarIsVisible = !m_bStatusBarIsVisible; } |
Code c++ : | Sélectionner tout |
1 2 3 4 5 | void CMainFrame::OnUpdateViewStatusBar(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_bStatusBarIsVisible); } |
On procédera comme suit :
Avec l'assistant générez une classe dérivée de la classe CStatusbar.
Générez ensuite les fonctions de réponse pour les messages WM_CREATE et WM_SIZE.
Rajoutez une variable contrôle CProgressCtrl comme donnée membre de la classe.
Enfin il faudra utiliser cette classe dans votre Mainframe en modifiant la déclaration de la variable initiale (CStatusBar).
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #pragma once // CStatusBarEx class CStatusBarEx : public CStatusBar { DECLARE_DYNAMIC(CStatusBarEx) public: CStatusBarEx(); virtual ~CStatusBarEx(); protected: CProgressCtrl m_Progress; DECLARE_MESSAGE_MAP() public: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnSize(UINT nType, int cx, int cy); }; |
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 | // StatusBarEx.cpp : fichier d'implémentation // #include "stdafx.h" #include "StatusBarEx.h" // CStatusBarEx IMPLEMENT_DYNAMIC(CStatusBarEx, CStatusBar) CStatusBarEx::CStatusBarEx() { } CStatusBarEx::~CStatusBarEx() { } BEGIN_MESSAGE_MAP(CStatusBarEx, CStatusBar) ON_WM_CREATE() ON_WM_SIZE() END_MESSAGE_MAP() // Gestionnaires de messages CStatusBarEx int CStatusBarEx::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CStatusBar::OnCreate(lpCreateStruct) == -1) return -1; // Initialise controls CRect rect( 0, 0, 100, 16); m_Progress.Create( WS_VISIBLE | WS_CHILD, rect, this, IDC_PROGRESS ); m_Progress.SetRange( static_cast<short>(0), static_cast<short>(100) ); return 0; } void CStatusBarEx::OnSize(UINT nType, int cx, int cy) { CStatusBar::OnSize(nType, cx, cy); // Initially create progress control in horizontal position CWnd* pWnd = (CWnd*)this; CRect rect; pWnd->GetWindowRect( &rect ); ScreenToClient( &rect ); if( m_Progress.GetSafeHwnd()) { m_Progress.SetWindowPos( &CWnd::wndTop, 0, 0, 100, 16, SWP_NOMOVE | SWP_NOZORDER); m_Progress.SetPos( 16); } } |
On pourra se reporter à ce post de la FAQ pour informations : Comment implanter des éléments dans une CStatusBar ?
On commence par créer un nouveau panneau dans le tableau indicators de la CMainFrame.
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 | static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_BMP, // panneau bitmap ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; |
Le nouvel identifiant doit être préalablement rajouté dans les ressources :
Sur le fichier .rc dans les ressources : clic droit ressources symbols.
On rajoutera aussi cet identifiant dans la string table.
L'étape suivante est de faire apparaitre le bitmap dans la barre d'états.
Pour cela il va falloir créer une classe héritée de CStatusbar pour placer notre traitement dans la méthode DrawItem , notre barre d'états devra donc posséder le style OwnerDraw pour le panneau concerné, ici le numéro 1.
La classe:
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #pragma once // CStatusBarEx class CStatusBarEx : public CStatusBar { DECLARE_DYNAMIC(CStatusBarEx) public: CStatusBarEx(); virtual ~CStatusBarEx(); void SetBitmap(UINT nId){m_BitmapId=nId;} protected: UINT m_BitmapId; DECLARE_MESSAGE_MAP() public: virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); }; |
Le 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 | #include "StatusBarEx.h" // CStatusBarEx IMPLEMENT_DYNAMIC(CStatusBarEx, CStatusBar) CStatusBarEx::CStatusBarEx():m_BitmapId(0) { } CStatusBarEx::~CStatusBarEx() { } BEGIN_MESSAGE_MAP(CStatusBarEx, CStatusBar) END_MESSAGE_MAP() // CStatusBarEx message handlers void CStatusBarEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { // TODO: Add your code to draw the specified item if(!m_BitmapId) return; CRect rect(lpDrawItemStruct->rcItem); CDC Memdc,barDC; barDC.Attach(lpDrawItemStruct->hDC); Memdc.CreateCompatibleDC(NULL); CBitmap Bmp; Bmp.LoadBitmap(m_BitmapId); BITMAP bmpInfo; Bmp.GetBitmap(&bmpInfo); CBitmap *poldBmp=Memdc.SelectObject(&Bmp); barDC.StretchBlt(rect.left,rect.top,rect.Width(),rect.Height(),&Memdc,0,0,bmpInfo.bmWidth,bmpInfo.bmHeight,SRCCOPY); Memdc.SelectObject(poldBmp); } |
Enfin il faut indiquer que le panneau 1 de notre barre d'état est OwnerDraw, on placera ce code dans la méthode OnCreate de la Mainframe :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | 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 } m_wndStatusBar.SetBitmap(IDB_BITMAP1); // affectation de l'identifiant du Bitmap dans les ressources m_wndStatusBar.SetPaneStyle(1,SBT_OWNERDRAW); // le panneau OwnerDraw. |
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.