Programming Microsoft Visual C++
The EX14B example replaces the standard application framework status bar with a new status bar that has the following text panes.
Pane Index | String ID | Type | Description |
0 | ID_SEPARATOR (0) | Message line | x cursor coordinate |
1 | ID_SEPARATOR (0) | Message line | y cursor coordinate |
2 | ID_INDICATOR_LEFT | Status indicator | Left mouse button status |
3 | ID_INDICATOR_RIGHT | Status indicator | Right mouse button status |
The resulting status bar is shown in Figure 14-4. Notice that the leftmost pane stretches past its normal 1/20-screen length as the displayed frame window expands.
Figure 14-4. The status bar of the EX14B example.
Follow these steps to produce the EX14B example:
- Run AppWizard to generate \vcpp32\ex14b\ex14b. Accept all default settings but two: select Single Document and deselect Printing and Print Preview. The options and the default class names are shown here.
- Use the string editor to edit the application's string table resource. The application has a single string table resource with artificial "segment" divisions left over from the 16-bit era. Double-click on the String Table icon in the String Table folder on the ResourceView page to bring up the string editor. Then double-click on the empty entry at the end of the list. A dialog allows you to assign the ID and the string value as shown below.
Add two strings as follows.
String ID String Caption ID_INDICATOR_LEFT LEFT ID_INDICATOR_RIGHT RIGHT - Use Visual C++ to edit the application's symbols. Choose Resource Symbols from the View menu. Add the new status bar identifier, ID_MY_STATUS_BAR, and accept the default value.
- Use ClassWizard to add View menu command handlers in the class CMainFrame. Add the following command message handlers.
Object ID Message Member Function ID_VIEW_STATUS_BAR COMMAND OnViewStatusBar ID_VIEW_STATUS_BAR UPDATE_COMMAND_UI OnUpdateViewStatusBar - Add the following function prototypes to MainFrm.h. You must add these CMainFrame message handler prototypes manually because ClassWizard doesn't recognize the associated command message IDs.
afx_msg void OnUpdateLeft(CCmdUI* pCmdUI); afx_msg void OnUpdateRight(CCmdUI* pCmdUI);
Add the message handler statements inside the AFX_MSG brackets so that ClassWizard will let you access and edit the code later. While MainFrm.h is open, make m_wndStatusBar public rather than protected.
- Edit the MainFrm.cpp file. Replace the original indicators array with the following boldface code:
static UINT indicators[] = { ID_SEPARATOR, // first message line pane ID_SEPARATOR, // second message line pane ID_INDICATOR_LEFT, ID_INDICATOR_RIGHT, };
Next edit the OnCreate member function. Replace the following statement
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 }
with the statement shown here:
if (!m_wndStatusBar.Create(this, WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, ID_MY_STATUS_BAR) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0("Failed to create status bar\n"); return -1; // fail to create }
The modified call to Create uses our own status bar ID, ID_MY_STATUS_BAR, instead of AFX_IDW_STATUS_BAR (the application framework's status bar object).
Now add the following message map entries for the class CMainFrame. ClassWizard can't add these for you because it doesn't recognize the string table IDs as object IDs.
ON_UPDATE_COMMAND_UI(ID_INDICATOR_LEFT, OnUpdateLeft) ON_UPDATE_COMMAND_UI(ID_INDICATOR_RIGHT, OnUpdateRight)
Next add the following CMainFrame member functions that update the two status indicators:
void CMainFrame::OnUpdateLeft(CCmdUI* pCmdUI) { pCmdUI->Enable(::GetKeyState(VK_LBUTTON) < 0); } void CMainFrame::OnUpdateRight(CCmdUI* pCmdUI) { pCmdUI->Enable(::GetKeyState(VK_RBUTTON) < 0); }
Note that the left and right mouse buttons have virtual key codes like keys on the keyboard have. You don't have to depend on mouse-click messages to determine the button status.
Finally, edit the following View menu functions that ClassWizard originally generated in MainFrm.cpp:
void CMainFrame::OnViewStatusBar() { m_wndStatusBar.ShowWindow((m_wndStatusBar.GetStyle() & WS_VISIBLE) == 0); RecalcLayout(); } void CMainFrame::OnUpdateViewStatusBar(CCmdUI* pCmdUI) { pCmdUI- >SetCheck((m_wndStatusBar.GetStyle() & WS_VISIBLE) != 0); }
These functions ensure that the View menu Status Bar command is properly linked to the new status bar.
- Edit the OnDraw function in Ex14bView.cpp. The OnDraw function displays a message in the view window. Add the following boldface code:
void CEx14bView::OnDraw(CDC* pDC) { pDC->TextOut(0, 0, "Watch the status bar while you move and click the mouse."); }
- Add a WM_MOUSEMOVE handler in the CEx14bView class. Use ClassWizard to map the message to OnMouseMove, and then edit the function as shown below. This function gets a pointer to the status bar object and then calls the SetPaneText function to update the first and second message line panes.
void CEx14bView::OnMouseMove(UINT nFlags, CPoint point) { CString str; CMainFrame* pFrame = (CMainFrame*) AfxGetApp()->m_pMainWnd; CStatusBar* pStatus = &pFrame->m_wndStatusBar; if (pStatus) { str.Format("x = %d", point.x); pStatus->SetPaneText(0, str); str.Format("y = %d", point.y); pStatus->SetPaneText(1, str); } }
Finally, add the statement
#include "MainFrm.h"
near the top of the file ex14bView.cpp.
- Build and test the EX14B application. Move the mouse, and observe that the left two status bar panes accurately reflect the mouse cursor's position. Try the left and right mouse buttons. Can you toggle the status bar on and off from the View menu?
If you want the first (index 0) status bar pane to have a beveled border like the other panes and you want the status bar to grow and resize to fit their contents, include the following two lines in the CMainFrame::OnCreate function, following the call to the status bar Create function.
m_wndStatusBar.SetPaneInfo(0, 0, 0, 50); m_wndStatusBar.SetPaneInfo(1, 0, SBPS_STRETCH, 50);
These statements change the width of the first two panes (from their default of one-fourth the display size) and make the second pane (index 1) the stretchy one.