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 FrameWorkBarre d'outils (11)
précédent sommaire suivant
 

Commencer par la définir dans l'éditeur de ressources.
Puis procéder à son initialisation dans la fonction OnCreate de la MdiChild qui est la classe parent (au sens Windows) de la fenêtre.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
  
int CMyMDIChildWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{ 
    if(CMDIChildWnd::OnCreate(lpCreateStruct) == -1) return -1; 
    // CToolBar  m_ToolBar; 
    if(!m_ToolBar.Create(this, WS_CHILD | WS_VISIBLE | CBRS_TOP) ||  
                                     !m_ToolBar.LoadToolBar(IDR_TOOLBAR)) 
    { 
        TRACE0("Failed to create toolbar\n"); 
        return -1;      // fail to create 
    } 
    return 0; 
}

Mis à jour le 5 avril 2013 farscape

Il faut gérer la notification de message ON_UPDATE_COMMAND_UI .
Avec l'aide de ClassWizard :

  • Sélectionner la classe fenêtre concernée.
  • Sélectionner l'id de la toolbar concernée

Dans la partie droite de l'écran deux notifications sont disponibles :

  • COMMAND: pour gérer l'action du click sur le bouton.
  • UPDATE_COMMAND_UI : pour gérer l'activité du bouton.

Exemple de notification générée par ClassWizard sur l'id ID_EDIT_CUT

Code c++ : Sélectionner tout
1
2
3
4
5
  
BEGIN_MESSAGE_MAP(CTestdlgBarMDIApp, CWinApp) 
//{{AFX_MSG_MAP(CTestdlgBarMDIApp) 
ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut) 
……….
La fonction:

Code c++ : Sélectionner tout
1
2
3
4
5
6
  
void CTestdlgBarMDIApp::OnUpdateEditCut(CCmdUI* pCmdUI)  
{ 
       // TODO: Add your command update UI handler code here 
       pCmdUI->Enable(m_bTestCut); // si m_bTestCut=false bouton grisé sinon actif. 
}

Mis à jour le 5 avril 2013 farscape

Principe : A la place du code classique de création de la toolbar dans la mainframe à partir de la fonction OnCreate , on écrira ceci :

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
  
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{ 
if (CFrameWnd::OnCreate(lpCreateStruct) == -1) 
return -1; 
  
if(!CreateToolBar()) return -1; 
  
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); 
  
return 0; 
}
La création de la toolbar est déplacée dans une fonction de création spécifique :

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
  
// ----------------------------------------------- 
BOOL CMainFrame::CreateToolBar() 
{ 
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 FALSE;      // fail to create 
} 
  
TBBUTTON button; 
  
button.iBitmap=NULL; 
button.idCommand=0; 
button.fsStyle=TBSTYLE_SEP; 
button.dwData=0; 
button.iString=NULL; 
m_wndToolBar.GetToolBarCtrl().InsertButton(0,&button); 
m_wndToolBar.GetToolBarCtrl().InsertButton(0,&button); 
m_wndToolBar.SetButtonInfo(0,1,TBBS_SEPARATOR,100); 
  
CRect rect; 
m_wndToolBar.GetItemRect(0,&rect); 
rect.top=2; 
rect.bottom=rect.top+100; 
  
if(!m_ComboBox.Create(CBS_DROPDOWNLIST | WS_VISIBLE | WS_TABSTOP,rect,&m_wndToolBar,1)) 
{ 
TRACE0("Failed to create combobox\n"); 
return FALSE;      // fail to create 
} 
  
m_ComboBox.AddString("item 0"); 
m_ComboBox.AddString("item 1"); 
m_ComboBox.AddString("item 2"); 
m_ComboBox.AddString("item 3"); 
return TRUE; 
}
On commence par insérer deux séparateurs avec la structure TBBUTTON et la fonction InserButton.
On fixe ensuite les infos sur le bouton à savoir son identifiant ici 1 et sa largeur en pixels :100.

Note : dans le cas d'un séparateur la fonction SetButtonInfo accepte la largeur en pixels au lieu de l'indice de l'image.
Voir documentation MSDN pour plus de détails.

Ensuite on récupère la place de l'item 0 et on lui recalcule sa hauteur.
On crée la ComboBox.
Et pour finir on l'alimente par AddString.

Pour manipuler les notifications on pourra rajouter la notification OnComboChange directement sur le message map de 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
  
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) 
//{{AFX_MSG_MAP(CMainFrame) 
ON_WM_CREATE() 
ON_WM_GETMINMAXINFO() 
//}}AFX_MSG_MAP 
ON_CBN_SELCHANGE(1,OnComboChange) 
END_MESSAGE_MAP() 
  
void CMainFrame::OnComboChange() 
{ 
//  
int nSel=m_ComboBox.GetCurSel(); 
if(nSel!=CB_ERR) 
{ 
CString str; 
m_ComboBox.GetLBText(nSel,str); 
TRACE("\nCombo Sel:%s",(const char *)str); 
} 
}

Mis à jour le 5 avril 2013 farscape

Proposition de classe :

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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  
///////////////////////////////////////////////////////////////////////////// 
// CToolBarEx window 
class CToolBarEx : public CToolBar 
{ 
// Construction 
public: 
CToolBarEx(); 
  
// Attributes 
public: 
    void  SetSizes(SIZE sizeButton, SIZE sizeImage) 
    { 
        GetToolBarCtrl( ).SetButtonSize(sizeButton); 
        if(GetToolBarCtrl( ).SetBitmapSize(sizeImage)) 
        m_sizeImage=sizeImage; 
    } 
  
   inline void InitSizes(CSize cSizeBitmapSize)  
    {  
        m_SizeButton=cSizeBitmapSize; 
        SetSizes(CSize(cSizeBitmapSize.cx+7,cSizeBitmapSize.cy+6),cSizeBitmapSize);  
        GetToolBarCtrl().AutoSize();     
    } 
    bool  SetButtonWidth(UINT nMinWidth,UINT nMaxWidth); 
    CSize GetButtonsWidth() const; 
    CSize GetButtonsSize()  const; 
  
    bool AddButtonToolBar(int nIndexPos,int nidCommand,UINT nIdbitmap,int istring=0); 
    bool DeleteButtonToolBar(int nIndexPos); 
  
    void RedrawToolBar(BOOL bRecalcLayout=TRUE,BOOL bOnlyFrame=FALSE); 
    void RedrawButton(int nIndex); 
    void UpdateSizes(); 
  
    void ReCalcDynamicLayout(CRect rect,int nIndexPos=-1); 
  
// Attributes 
private: 
    CSize m_sizeMiniMaxi; 
    CSize m_SizeButton; 
    CSize m_sizeImage; 
  
// Operations 
public: 
  
// Overrides 
// ClassWizard generated virtual function overrides 
//{{AFX_VIRTUAL(CToolBarEx) 
//}}AFX_VIRTUAL 
  
// Implementation 
public: 
virtual ~CToolBarEx(); 
  
// Generated message map functions 
protected: 
//{{AFX_MSG(CToolBarEx) 
// NOTE - the ClassWizard will add and remove member functions here. 
//}}AFX_MSG 
  
DECLARE_MESSAGE_MAP() 
}; 
  
///////////////////////////////////////////////////////////////////////////// 
// CToolBarEx 
  
CToolBarEx::CToolBarEx() 
{ 
    m_SizeButton.cx=16; 
    m_SizeButton.cy=15; 
} 
  
CToolBarEx::~CToolBarEx() 
{ 
} 
  
  
BEGIN_MESSAGE_MAP(CToolBarEx, CToolBar) 
//{{AFX_MSG_MAP(CToolBarEx) 
// NOTE - the ClassWizard will add and remove mapping macros here. 
//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
  
///////////////////////////////////////////////////////////////////////////// 
// CToolBarEx message handlers 
bool CToolBarEx::SetButtonWidth(UINT nMinWidth,UINT nMaxWidth) 
{  
    ASSERT(::IsWindow(GetSafeHwnd())); 
    ASSERT(nMaxWidth-m_sizeImage.cx>=7); 
    if(SendMessage(TB_SETBUTTONWIDTH, 0, MAKELPARAM(nMinWidth, nMaxWidth))) 
    { 
        m_sizeMiniMaxi.cx=nMinWidth; 
        m_sizeMiniMaxi.cy=nMaxWidth; 
        return true; 
    } 
    return false;  
} 
//---------------------------------------------------------------- 
CSize CToolBarEx::GetButtonsWidth() const 
{  
    ASSERT(::IsWindow(GetSafeHwnd())); 
    return m_sizeMiniMaxi;  
} 
//---------------------------------------------------------------- 
CSize CToolBarEx::GetButtonsSize() const 
{  
    ASSERT(::IsWindow(GetSafeHwnd())); 
    DWORD result=(DWORD)::SendMessage(m_hWnd,TB_GETBUTTONSIZE,0,(LPARAM)0);  
    return CSize(LOWORD(result),HIWORD(result));  
} 
//---------------------------------------------------------------- 
void CToolBarEx::RedrawToolBar(BOOL bRecalcLayout/*=TRUE*/,  
   BOOL bOnlyFrame/*=FALSE*/) 
{ 
    ASSERT(::IsWindow(GetSafeHwnd())); 
  
    if(!IsWindowVisible())return; 
  
    if(bRecalcLayout) 
    { 
        CWnd *pParent=GetToolBarCtrl( ).GetParent(); 
        CFrameWnd* pFrameWnd=(CFrameWnd *)pParent->GetParent(); 
        if(pFrameWnd!=NULL) 
        { 
            pFrameWnd->RecalcLayout(); 
            for(int nIndex=0; nIndex<GetToolBarCtrl( ).GetButtonCount(); nIndex++) 
            { 
                RedrawButton(nIndex); 
                CRect rect; 
                GetItemRect(nIndex,rect); 
                ValidateRect(rect); 
            } 
        } 
    } 
    else 
    { 
        if(!bOnlyFrame) 
        { 
            GetToolBarCtrl( ).RedrawWindow(NULL,NULL, 
            RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME|RDW_ALLCHILDREN); 
        } 
    } 
    if(bOnlyFrame) 
    { 
        GetToolBarCtrl( ).SetWindowPos(NULL,0,0,0,0, 
        SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_DRAWFRAME); 
    } 
} 
//---------------------------------------------------------------- 
void CToolBarEx::RedrawButton(int nIndex) 
{ 
    ASSERT(::IsWindow(GetSafeHwnd())); 
  
    if(nIndex<0 || nIndex>GetToolBarCtrl().GetButtonCount()) 
    { 
        return; 
    } 
    CRect rect; 
    GetToolBarCtrl( ).GetItemRect(nIndex,rect); 
    GetToolBarCtrl( ).RedrawWindow(rect); 
} 
//---------------------------------------------------------------- 
void CToolBarEx::UpdateSizes()  
{  
    SetSizes(GetButtonsSize(),m_sizeImage);  
    GetToolBarCtrl().AutoSize(); 
} 
//---------------------------------------------------------------- 
bool CToolBarEx::DeleteButtonToolBar(int nIndexPos) 
{ 
    CRect rect;  
    GetToolBarCtrl( ).GetWindowRect(&rect); 
  
    if(!GetToolBarCtrl( ).DeleteButton(nIndexPos)) return false; 
  
    // resize window  
    rect.right-=(m_SizeButton.cx+7); 
    SetWindowPos(NULL,0,0,rect.Width(),rect.Height(), 
    SWP_NOMOVE|SWP_NOZORDER|SWP_DRAWFRAME|SWP_FRAMECHANGED); 
  
    ReCalcDynamicLayout(rect); 
    return true; 
} 
//---------------------------------------------------------------- 
void CToolBarEx::ReCalcDynamicLayout(CRect rect,int nIndexPos/*=-1*/) 
{ 
    SetWindowPos(NULL,0,0,rect.Width(),rect.Height(), 
        SWP_NOMOVE|SWP_NOZORDER|SWP_DRAWFRAME|SWP_FRAMECHANGED); 
  
    if(IsFloating())   
    { 
        CPoint newPos(0,0);         
        ClientToScreen(&newPos); 
        CRect rcNew; 
        //  GetToolBarCtrl().SetRows(GetToolBarCtrl().GetRows(),TRUE, &rcNew); 
  
        CalcDynamicLayout(rect.Width(),LM_HORZ | LM_COMMIT); 
  
        CWnd *pParent=GetToolBarCtrl( ).GetParent(); 
        CFrameWnd* pFrameWnd=(CFrameWnd *)pParent->GetParent(); 
  
        if(pFrameWnd) 
            pFrameWnd->FloatControlBar(this, newPos,CBRS_ALIGN_TOP | CBRS_SIZE_DYNAMIC); 
    } 
  
    RedrawToolBar(); 
    if(nIndexPos>0)RedrawButton(nIndexPos); 
  
} 
//---------------------------------------------------------------- 
bool CToolBarEx::AddButtonToolBar(int nIndexPos,int nidCommand,UINT nIdbitmap,int istring/*=0*/) 
{ 
    BOOL bok; 
  
    CRect rect;  
    GetToolBarCtrl( ).GetWindowRect(&rect); 
  
    TBBUTTON Buttons; 
    GetToolBarCtrl( ).AddBitmap(1,nIdbitmap); 
    Buttons.iBitmap=nIndexPos; 
    Buttons.idCommand=nidCommand; 
    Buttons.fsState=TBSTATE_ENABLED; 
    Buttons.fsStyle=TBSTYLE_BUTTON; 
    Buttons.dwData=0; 
    Buttons.iString=istring; 
    bok=GetToolBarCtrl( ).AddButtons(1,&Buttons); 
  
    SetButtonWidth(0,m_SizeButton.cx+7); 
  
    InitSizes(m_SizeButton); 
  
    // resize window  
    rect.right+=(m_SizeButton.cx+7); 
  
    ReCalcDynamicLayout(rect,nIndexPos); 
    return (bok?true:false); 
}
Initialisations dans 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
  
// portion de code relatif à la CToolbarEx 
    if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_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 
} 
  
m_wndToolBar.InitSizes(CSize(16,15)); 
  
m_wndToolBar.SetWindowText(_T("Toolbar")); 
m_wndToolBar.UpdateSizes(); 
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); 
  
// 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);
Notez l'utilisation du style CBRS_SIZE_DYNAMIC ,
l'utilisation de la fonction InitSizes pour spécifier la taille des boutons , et la fonction UpdateSizes() pour la prise en compte des modifications.

Utilisation:

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
  
// rajout d'un bouton par un bitmap IDB_BITMAP1 a la position 8 associé a la commande ID_BUTTONADD 
CMainFrame * pMain=(CMainFrame *)AfxGetMainWnd();   
pMain->m_wndToolBar.AddButtonToolBar(8,ID_BUTTONADD,IDB_BITMAP1); 
  
// del d'un bouton  
CMainFrame * pMain=static_cast<CMainFrame *>(AfxGetMainWnd());   
pMain->m_wndToolBar.DeleteButtonToolBar(8);
Dans le code ci-dessus l'ajout d'un bouton prend en charge le recalcul et le dessin de la CToolBar qu'elle soit ancrée ou non.
Deux méthodes sont utilisées suivant que la CToolBar est ancrée ou non ,le détail du traitement est visible dans la fonction ReCalcDynamicLayout.

Mis à jour le 5 avril 2013 farscape

En surchargeant la fonction virtuelle CalcFixedLayout pour enlever le style WS_SYSMENU à la fenêtre.

Code c++ : Sélectionner tout
1
2
3
4
5
6
  
CControlBar::CalcFixedLayout 
Cette méthode calcul la taille horizontal d'une barre de contrôle  
virtual CSize CalcFixedLayout( 
BOOL bStretch, 
BOOL bHorz );
Implémentation :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
  
CSize CMyToolBar::CalcFixedLayout( BOOL bStretch, BOOL bHorz ) 
{ 
    if ( IsFloating() ) // only when we float 
    GetParent()->GetParent()->ModifyStyle( WS_SYSMENU, 0 );  
    return CToolBar::CalcFixedLayout( bStretch, bHorz ); 
}

Mis à jour le 5 avril 2013 farscape

Visual C++ reconnaît les contrôles communs d'Internet Explorer. Parmi eux, la rebar (CRebar).
Ce contrôle est en fait un conteneur dans lequel on peut mettre des barres d'outils (CToolBar et CDialogBar).
On appelle bande chaque barre d'outils, et on désignera par barre d'outils l'ensemble des bandes.

Pour que l'application intègre une rebar, il faut cocher l'option "Internet Explorer Rebars" à l'étape 4 de l'AppWizard dans la section "How do you want your toolbars look ?".
A l'exécution, on voit que la barre d'outils comporte 2 bandes : la toolBar classique avec ses boutons, et une dialogBar avec la mention "A FAIRE : Disposez la barre de dialogue".

La classe MainFrame possède les données membres suivantes :

Code c++ : Sélectionner tout
1
2
3
4
5
protected:  // control bar embedded members 
CStatusBar  m_wndStatusBar;  // barre d'état 
CToolBar    m_wndToolBar;  // barre d'outils classique 
CReBar      m_wndReBar;  // la rebar 
CDialogBar  m_wndDlgBar;  // la barre de dialogue
et la rebar est créée de la façon suivante :

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
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{ 
... 
  
   // création de la toolbar 
   if (!m_wndToolBar.CreateEx(this) || 
      !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) 
   {  
      TRACE0("Failed to create toolbar\n"); 
      return -1;      // fail to create 
   } 
  
   // création de la dialogbar 
   if (!m_wndDlgBar.Create(this, IDR_MAINFRAME,  
      CBRS_ALIGN_TOP, AFX_IDW_DIALOGBAR)) 
   { 
      TRACE0("Failed to create dialogbar\n"); 
      return -1;// fail to create 
   } 
  
   // création de la rebar et ajout de la toolbar et de la dialogbar 
   if (!m_wndReBar.Create(this) || 
       !m_wndReBar.AddBar(&m_wndToolBar) || 
       !m_wndReBar.AddBar(&m_wndDlgBar)) 
   { 
      TRACE0("Failed to create rebar\n"); 
      return -1;      // fail to create 
   } 
  
... 
  
   return 0; 
}
Maintenant, ajoutez les contrôles sur la dialogbar comme pour une fenêtre de dialogue classique (vous pouvez ajouter n'importe quel contrôle de base ou perso, et changer la taille de la dialogbar). Associez cette dernière à la classe CMainFrame. Dans l'éditeur double-cliquez sur la dialogbar, à l'invite "Adding a class" choisissez "Select an existing class" puis OK.
A l'invite suivante, choisissez CMainFrame dans la liste puis validez.
On choisit CMainFrame et non une nouvelle classe de dialogue car on veut ajouter une barre d'outils et non pas une nouvelle classe de dialogue.
Ensuite, programmez les gestionnaires des contrôles de la rebar (i.e. de la dialogbar de la rebar).

Mis à jour le 20 mai 2006 bigboomshakala

Les barres de dialogue ou barres d'outils sont créées habituellement dans la fonction OnCreate de la mainframe de l'application et éventuellement dans la MDIChild (en plus) dans un contexte MDI.
Ce cas de figure fonctionne très bien si le composant est visible dès sa création.
Si celui-ci est créé en mode caché ou s'il est créé à un autre moment que la fonction OnCreate celui-ci n'apparaît pas.

On utilisera alors la fonction RecalcLayout pour provoquer le rafraîchissement des barres d'outils ou barre de dialogue.

Exemple avec la création dynamique d'une barre de dialogue:

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
  
void CMyMDIChild::CreateDialogBar() 
   { 
       m_pDlgBar = new CDialogBar(); 
       m_pDlgBar->Create(this,IDD_CHILDBAR,CBRS_TOP,115); 
       RecalcLayout(); 
   }

Mis à jour le 20 mai 2006 farscape

Ou plutôt comment sauvegarder automatiquement et à chaque fermeture du programme la dernière position de toutes ses barres d'outils et de barres de dialogue? Et pas seulement la position, sa visibilité, si elle était flottante ou non, etc... Pour cela, il suffit tout simplement d'utiliser les fonctions SaveBarState() et LoadBarState() de la classe CFrameWnd.

Lorsque l'on ferme l'application, il suffit de surcharger la fonction OnClose() de la classe CMainFrame() comme suit :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  
void CMainFrame::OnClose() 
{ 
// TODO: Add your message handler code here and/or call default 
  
/* 
* Ici on ajoute la sauvegarde de toutes les barres d'outils présentes 
* dans le projet grâce à la fonction SaveBarState. Cette fonction 
* prend comme argument le nom de la clef dans lequel sera stocké 
* les informations dans la base de registres. 
*/ 
this->SaveBarState("Clef_Ammont\\Ici_Ma_Sauvegarde"); 
  
CMDIFrameWnd::OnClose(); // appel de la fonction de base 
}

Cette fonction n'est pas présente par défaut, il faut rajouter un "handler" en utilisant le wizard de visual c++ sur le message WM_CLOSE.

Voilà pour la sauvegarde, et maintenant pour récupérer les données il suffit de faire lors de la création des barres d'outils dans la MainFrame l'opération inverse à un détail près.
Il faut effectivement lors de la création des barres d'outils renseigner celles-ci de leur propre ID, car hélas, pour des raisons obscures, ils ne sont pas mémorisés lors de l'appel de la fonction Create()...
Pour cela, il suffit d'appeler la fonction SetDlgCtrlID du contrôle de la barre pour leur affecter leur propre ID après que celle-ci ait été créée.
Le plus souvent, la création des toolbars se fait dans la fonction OnCreate() du MainFrame.
Ainsi, il suffit de la modifier comme suit pour obtenir le fonctionnement désiré :

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
  
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 
} 
  
/* 
* Attribution de l'ID au control car n'est pas effectué lors de la 
* création. Il faut impérativement le faire sinon cela fera planter 
* le programme lorsque plusieurs toolbars seront flottantes!! 
* Il faut également s'assurer que les ids soient différents d'une 
* barre à l'autre!! 
*/ 
m_wndToolBar.SetDlgCtrlID(IDR_MAINFRAME); 
  
if (!m_wndToolBar2.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | 
WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | 
CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || 
!m_wndToolBar2.LoadToolBar(IDR_MAINFRAME2)) 
{ 
TRACE0("Failed to create toolbar\n"); 
return -1; // fail to create 
} 
  
/* 
* Attribution de l'ID au control car n'est pas effectué lors de la 
* création. Il faut impérativement le faire sinon cela fera planter 
* le programme lorsque plusieurs toolbars seront flottantes!! 
* Il faut également s'assurer que les ids soient différents d'une 
* barre à l'autre!! 
*/ 
m_wndToolBar2.SetDlgCtrlID(IDR_MAINFRAME2); 
  
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 
} 
  
/* 
* La barre de status n'a pas besoin d'être mémorisée, sa position 
* ne varie pas car elle n'est pas "Dockable". 
*/ 
  
// TODO: Delete these three lines if you don't want the toolbar to 
// be dockable 
EnableDocking(CBRS_ALIGN_ANY); 
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); 
m_wndToolBar2.EnableDocking(CBRS_ALIGN_ANY); 
DockControlBar(&m_wndToolBar); 
DockControlBar(&m_wndToolBar2); 
  
/* 
* C'est ici, APRES toutes les initialisations que doit être effectué 
* la récupération des positions des barres d'outils. Assurez-vous 
* que les barres soient créées avant que cette fonction soit appellée 
* et avant que EnableDocking soit appellé également. 
*/ 
LoadBarState("Clef_Ammont\\Ici_Ma_Sauvegarde"); 
  
return 0; 
}

Voilà, il n'y a plus qu'à compiler et à essayer!! Je n'ai eu aucun problème avec Visual C++ V6.
Ceci fonctionne avec toutes les classes dérivées de CControlBar.
Note : Cela n'a d'intérêt que si les barres d'outils sont "Dockables"!! Voir la fonction EnableDocking() pour plus d'infos.

Mis à jour le 22 janvier 2007 GuileUkow

Il est parfois utile de disposer pour le bouton d'une barre d'outils d'un deuxième état.
L'exemple le plus simple étant par exemple un bouton avec une icône de lecture par défaut et lorsqu'il est actionné l'image stop apparaît.
Ou un cadenas ouvert puis fermé indiquant visuellement qu'une action est interdite.

Le principe :
Il suffira de rajouter un bitmap pour visualiser le nouvel état du bouton dans la barre d'outils
Et de le permuter avec l'image initiale après que le bouton ait été pressé .

Concrètement le traitement se passera dans la MDIChild dans le cas d'un projet MDI où la MainFrame pour un projet SDI.
On pourra aussi faire une classe dérivée de CToolBar et inclure ces fonctionnalités dedans..

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
  
class CChildFrame : public CMDIChildWnd 
{ 
    DECLARE_DYNCREATE(CChildFrame) 
public: 
    CChildFrame(); 
  
// Attributes 
public: 
CToolBar    m_wndToolBar; 
  
// Operations 
public: 
    struct CUSTOMBT 
    { 
        int nIndiceOrg; 
        int nIndiceNew; 
        CString strNewTxt; 
        CString strOldtxt; 
    }; 
    // fixe le deuxieme etat (bitmap) pour le bouton nIDBt. 
    void      SetButton(int nIDBt,UINT nBitmapID,const char *szNextText); 
  
    // mise à jour de l'état du bouton  
    int        UpdateButton(int nIDBt); 
  
    // fixe le numero d'image pour le bouton nIDBt 
    BOOL    SetButtonImage(int nIDBt,int nImage); 
  
   // recupere le numero d'image pour le bouton nIDBt 
    BOOL    GetButtonImage(int nIDBt,int &rnImage); 
  
    // rajoute un bitmap à la barre d'outils. 
    BOOL    AddBitmapToolBar(int nNumButtons,UINT nBitmapID ); 
  
    // fixe l'etat visuel du bouton dans la barre d'outils pressé/non préssé. 
    BOOL    SetButtonPressed(int nIDBt,bool bPressed=true); 
  
    // met a jour le statut du bouton et renvoie TRUE si il est pressé. 
    BOOL IsButtonPressed(int nIDBt,bool bMajBt=true); 
  
   // renvoie le nombre de button dans la barre d'outil. 
    int       GetButtonCount(); 
  
private: 
    CMap<UINT ,UINT ,struct CUSTOMBT ,struct CUSTOMBT> m_mapCustomBt; 
//......................
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
  
//---------------------------------------------------------------- 
int CChildFrame::UpdateButton(int nIDBt) 
{ 
    struct CUSTOMBT custom; 
  
    if(!m_mapCustomBt.Lookup(nIDBt,custom)) return -1; 
  
    int rnImage; 
    if(GetButtonImage(nIDBt,rnImage)) 
    {                     
        rnImage=(rnImage==custom.nIndiceNew?custom.nIndiceOrg:custom.nIndiceNew); 
  
        SetButtonImage(nIDBt,rnImage); 
  
        // met le bouton enfoncé dans le cas du deuxieme etat. 
        SetButtonPressed(nIDBt,rnImage==custom.nIndiceNew); 
        return (rnImage==custom.nIndiceNew); 
    } 
    return -1; 
} 
//---------------------------------------------------------------- 
void CChildFrame::SetButton(int nIDBt,UINT nBitmapID,const char *szNextText) 
{ 
    struct CUSTOMBT custom; 
  
    int nNumButtons=m_wndToolBar.GetToolBarCtrl().GetImageList()->GetImageCount(); 
    custom.nIndiceNew=AddBitmapToolBar(nNumButtons,nBitmapID); 
  
    custom.strNewTxt=szNextText; 
  
    GetButtonImage(nIDBt,custom.nIndiceOrg); 
  
    m_mapCustomBt.SetAt(nIDBt,custom); 
} 
//---------------------------------------------------------------- 
BOOL CChildFrame::SetButtonImage(int nIDBt,int nImage) 
{ 
  
    TBBUTTONINFO tbbi; 
    tbbi.dwMask = TBIF_IMAGE; 
    tbbi.cbSize = sizeof tbbi; 
  
    BOOL b=m_wndToolBar.GetToolBarCtrl().GetButtonInfo(nIDBt, &tbbi ); 
    if(b) 
    { 
        tbbi.iImage=nImage;         
        b=m_wndToolBar.GetToolBarCtrl().SetButtonInfo(nIDBt,&tbbi); 
        m_wndToolBar.GetToolBarCtrl().RedrawWindow(); 
    } 
    return (b && b!=-1); 
}  
//---------------------------------------------------------------- 
BOOL CChildFrame::GetButtonImage(int nIDBt,int &rnImage) 
{ 
   char sztext[256]; 
  
   TBBUTTONINFO tbbi; 
   tbbi.dwMask = TBIF_IMAGE; 
  
   tbbi.cbSize = sizeof tbbi; 
  
   BOOL b= m_wndToolBar.GetToolBarCtrl().GetButtonInfo(nIDBt, &tbbi ); 
  
   rnImage=tbbi.iImage; 
  
  
   return (b && b!=-1); 
}  
//---------------------------------------------------------------- 
  
BOOL CChildFrame::AddBitmapToolBar(int nNumButtons,UINT nBitmapID ) 
{      
   return m_wndToolBar.GetToolBarCtrl().AddBitmap(nNumButtons,nBitmapID); 
} 
//---------------------------------------------------------------- 
int CChildFrame::GetButtonCount() 
{ 
    // nombre de boutons dans la toolbar separateur compris. 
    int nct=m_wndToolBar.GetToolBarCtrl().GetButtonCount(); 
    int nCount=0; 
    TBBUTTON tb; 
    for(int i=0;i<nct;i++) 
    { 
        m_wndToolBar.GetToolBarCtrl().GetButton(i,&tb); 
        // si l'indice commande du bouton est valide ok on a bien un bouton. 
        if(tb.idCommand) nCount++; 
    } 
    return nCount; 
} 
//---------------------------------------------------------------- 
BOOL CChildFrame::SetButtonPressed(int nIDBt,bool bPressed/*=true*/) 
{ 
   int nState=TBSTATE_ENABLED ; 
   if(bPressed) nState|=TBSTATE_PRESSED; 
  
   return m_wndToolBar.GetToolBarCtrl().SetState(nIDBt,nState); 
} 
//---------------------------------------------------------------- 
BOOL CChildFrame::IsButtonPressed(int nIDBt,bool bMajBt/*=true*/) 
{ 
    if(bMajBt) UpdateButton(nIDBt); 
    return m_wndToolBar.GetToolBarCtrl().IsButtonPressed(nIDBt);         
}

Utilisation dans la vue:

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
  
void CTestToolBarView::OnInitialUpdate() 
{ 
    CFormView::OnInitialUpdate(); 
    ResizeParentToFit(); 
  
    // acces à la frame (parent de la classe fenetre). 
    CChildFrame *pChild=static_cast<CChildFrame *>(GetParentFrame()); 
  
    // ajout du bitmap en fin de toolbar . 
  
    pChild->SetButton(ID_BUTTONOPENCLOSE,IDB_BITMAPCLOSE,""); 
    pChild->SetButton(ID_BUTTONOPENCLOSE2,IDB_BITMAPCLOSE2,""); 
} 
//---------------------------------------------------------------- 
void CTestToolBarView::OnButtonopenclose()  
{ 
    // TODO: Add your command handler code here 
    int rnImage; 
    CChildFrame *pChild=static_cast<CChildFrame *>(GetParentFrame());   
    if(pChild->IsButtonPressed(ID_BUTTONOPENCLOSE)) 
    { 
        TRACE("\nID_BUTTONOPENCLOSE:Pressé"); 
    } 
    else 
    { 
        TRACE("\nID_BUTTONOPENCLOSE:relaché"); 
    } 
} 
  
void CTestToolBarView::OnButtonopenclose2()  
{ 
    // TODO: Add your command handler code here 
    int rnImage; 
    CChildFrame *pChild=static_cast<CChildFrame *>(GetParentFrame());       
    if(pChild->IsButtonPressed(ID_BUTTONOPENCLOSE2)) 
    { 
        TRACE("\nID_BUTTONOPENCLOSE2:Pressé"); 
    } 
    else 
    { 
        TRACE("\nID_BUTTONOPENCLOSE2:relaché"); 
    }     
}

L'utilisateur définit pour le bouton spécifié le nouveau bitmap.

Exemple:

Mis à jour le 22 janvier 2007 farscape

On procédera comme suit :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  
if(pToolBar->IsFloating()) 
{ 
    CRect rect; 
    pToolBar->GetWindowRect(rect);             
  
    pToolBar->SetWindowPos(NULL,0,0,rect.Width(),rect.Height(), 
     SWP_NOMOVE|SWP_NOZORDER|SWP_DRAWFRAME|SWP_FRAMECHANGED); 
  
    CPoint newPos(0,0); 
    pToolBar->ClientToScreen(&newPos); 
    CRect rcNew; 
  
    pToolBar->CalcDynamicLayout(rect.Width(),LM_HORZ | LM_COMMIT); 
  
    ParentWindow->FloatControlBar(pToolBar, newPos, 
         CBRS_ALIGN_TOP | CBRS_SIZE_DYNAMIC);  
}

Mis à jour le 22 janvier 2007 farscape

Par défaut lorsqu'on déclare deux barres d'outils dans la MainFrame le positionnement se fait sur deux lignes.
Pour positionner les deux barres d'outils sur la même ligne on procédera comme suit :

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
  
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{ 
    if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) 
        return -1; 
  
    if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_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 
    }     
    m_wndToolBar.SetWindowText(_T("Toolbar"));     
    m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); 
  
// deuxieme toolbar . 
    if (!m_wndToolBar2.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP 
        | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || 
        !m_wndToolBar2.LoadToolBar(IDR_MAINFRAME)) 
    { 
        TRACE0("Failed to create toolbar\n"); 
        return -1;      // fail to create 
    } 
  
    m_wndToolBar2.SetWindowText(_T("Toolbar2"));     
    m_wndToolBar2.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); 
  
    // TODO: Delete these three lines if you don't want the toolbar to 
    //  be dockable 
    m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); 
        m_wndToolBar2.EnableDocking(CBRS_ALIGN_ANY); 
  
       EnableDocking(CBRS_ALIGN_ANY); 
       DockControlBar(&m_wndToolBar); //placement 1 toolbar 
  
       CRect RectOne,RectTwo; 
       RecalcLayout(); 
  
    m_wndToolBar.GetWindowRect(&RectOne); 
  
    m_wndToolBar2.GetWindowRect(&RectTwo); 
    int nWidth=RectTwo.Width(); 
    int nHeight=RectTwo.Height(); 
  
// calcul emplacement de la toolbar2 a droite de la 1 toolbar 
    RectTwo.left=RectOne.right; 
    RectTwo.right=RectTwo.left+nWidth; 
    RectTwo.top=RectOne.top; 
    RectTwo.bottom=RectTwo.top+nHeight; 
  
// placement final. 
    DockControlBar(&m_wndToolBar2,(UINT)0,RectTwo); 
    RecalcLayout();     
  
    return 0; 
}


Dans mon exemple c'est la même barre d'outils qui est associée à deux variables différentes.

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 © 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++