问题
- 按msdn上的教程在CWnd派生的窗口的OnCreate下创建CToolBar,工具栏不显示。
- Create a toolbar resource.
- Construct the CToolBar object.
- Call the Create (or CreateEx) function to create the Windows toolbar 4. and attach it to the CToolBar object.
- Call LoadToolBar to load the toolbar resource
- 由CFrameWnd派生的窗口的OnCreate按上文提到的方法在OnCreate丰创建CToolBar, 工具栏显示了,但显示的图片都是位图的第一张
探究
- 问题1
由CWnd直接派生的窗口下创建不显示,第一个我想到的就是CToolBar的窗口大小没设置,导致不显示,在代码中印证了下,果然如此,
m_ToolBar.CreateEx( this );
m_ToolBar.LoadToolBar( IDR_TOOLBAR1 );
m_ToolBar.SetButtons( NULL, 3 );
m_ToolBar.SetButtonText( 0, _T("button1") );
m_ToolBar.SetButtonText( 0, _T("button2") );
m_ToolBar.SetButtonText( 0, _T("button3") );
m_ToolBar.MoveWindow( 20, 20, 200, 50 );
显示如下
上面手动设置,工具栏是显示出来,但是位置、大小都要自己手动去管理,非常麻烦。由CFrameWnd直接派生的窗口下创建就可以显示,而且是自动管理位置、大小的。基于以上事实,那么很容易想到是不是CFrameWnd对工具栏做过什么特别的管理呢。通过网上查找相关资料,查看MFC对CFrameWnd的实现源码,印证了我的推断,代码如下:
void CFrameWnd::RecalcLayout(BOOL bNotify)
{
if (m_bInRecalcLayout)
return;
m_bInRecalcLayout = TRUE;
// clear idle flags for recalc layout if called elsewhere
if (m_nIdleFlags & idleNotify)
bNotify = TRUE;
m_nIdleFlags &= ~(idleLayout|idleNotify);
#ifndef _AFX_NO_OLE_SUPPORT
// call the layout hook -- OLE support uses this hook
if (bNotify && m_pNotifyHook != NULL)
m_pNotifyHook->OnRecalcLayout();
#endif
// reposition all the child windows (regardless of ID)
if (GetStyle() & FWS_SNAPTOBARS)
{
CRect rect(0, 0, 32767, 32767);
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery,
&rect, &rect, FALSE);
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra,
&m_rectBorder, &rect, TRUE);
CalcWindowRect(&rect);
SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(),
SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
}
else
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, &m_rectBorder);
m_bInRecalcLayout = FALSE;
}
从以上代码中可以看出,CFrameWnd在调整窗口布局时,调用了CWnd::RepositionBars去调整Bars的位置,此函数内部会依次遍历子窗口,并向子窗口发送WM_SIZEPARENT消息。就此打住,就不继续深入进去了。
- 问题2
原因在于m_ToolBar.SetButtons( NULL, 3 )
的第一个参数 传递的是NULL,即没有对各个按钮进行位图的初始化,由MFC源码得知,MSDN上也有提到:
If lpIDArray is NULL, this function allocates space for the number of items specified by nIDCount. Use SetButtonInfo to set each item’s attributes.
解决
- 探究了问题1后,我想最快的解决办法就是从CFrameWnd派生,这样就让CFrameWnd去操心这些Bars吧
- 问题2的话就很简单了,不多说了,看MSDN
总结
在MFC下,如果不想使用单文档/多文档的结构,但又想使用工具栏、状态栏等一些Bars的话,就从CFrameWnd下派生窗口类,这样就能轻松拥有这些Bars了。