适用于
这一个文章先前在 Q298126 之下被出版
征兆
当一个 MFC 工具栏垂直地被放置,工具栏的定制可能造成一个或更多个按纽不能显示。 定制可能使用CToolBarCtrl的Customize()函数 增加或除去按纽或相似的编程方法。
原因
首先, MFC 提供 对象的所有细节 , 像是工具栏 , 但是自从4.0版本,MFC 开始MFC开始用公用控件来代替工具柆,状态栏等等的实现。这个导置了MFC控件类的兼容性。
解决
无论工具栏是停靠或悬浮,在增加或删除按纽后,以下代码能够正确地调整大小,重画MFC垂直工具栏。 OnToolBarChange的句柄 响应 TBN_TOOLBARCHANGE 通知被执行。 代码分三个步骤执行。 首先, CalcDynamicLayout以适当的参数执行,工具栏的状态可能为停靠/ 悬浮/垂直/ 水平。 其次, DockControlBar( 或 FloatControlBar) 被执行, 主要地呼叫这些函数来执行 SetWindowPos 的呼叫。 最后, DrawBorders 被呼叫完成重画。
把下列的注册加入你 CMainFrame's 的信息映象中。 (AFX_IDW_TOOLBAR 是工具栏ID)
ON_NOTIFY(TBN_TOOLBARCHANGE, AFX_IDW_TOOLBAR, OnToolBarChange)
把 OnToolBarChange 成员函数加入 CMainFrame 类并且增加下列的代码:
void CMainFrame::OnToolBarChange(NMHDR *notify, LRESULT *result)
{
// Update the toolbar icons.
CFrameWnd* pFrame;
if (m_wndToolBar.IsFloating())
pFrame = m_wndToolBar.GetParentFrame();
else
pFrame = m_wndToolBar.GetDockingFrame();
CRect rectActualSize;
CRect rectActualFrameSize;
CRect rect;
CSize size;
// Get the ToolBar's rectangle
m_wndToolBar.GetWindowRect(&rect);
// Are we horizontal?
BOOL bHorz = (m_wndToolBar.m_dwStyle & CBRS_ORIENT_HORZ) != 0;
if ((m_wndToolBar.m_dwStyle & CBRS_FLOATING) &&
(m_wndToolBar.m_dwStyle & CBRS_SIZE_DYNAMIC))
size = m_wndToolBar.CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH |
LM_COMMIT);
else if (bHorz)
size = m_wndToolBar.CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK |
LM_COMMIT);
else
size = m_wndToolBar.CalcDynamicLayout(0, LM_VERTDOCK | LM_COMMIT);
// Use the result to calculate a new size
rectActualSize = CRect(rect.TopLeft(), size);
rectActualFrameSize = CRect(rect.TopLeft(), size);
// Calculate frame rectangle
CMiniFrameWnd::CalcBorders(rectActualFrameSize);
// Leave room for the window's border. The values used here
// for m_cxBorder and m_cyBorder are 2 and 2 as a result of
// calling GetSystemMetrics for SM_CXBORDER and SM_CYBORDER
// (these should return 1) and multiplying the result by 2
// to accommodate the modern shell's wider borders.
rectActualFrameSize.InflateRect(-m_cxBorder, -m_cyBorder);
if (m_wndToolBar.IsFloating())
{
pFrame->FloatControlBar(&m_wndToolBar,
rectActualFrameSize.TopLeft());
}
else
pFrame->DockControlBar(&m_wndToolBar);
// force the frame window to recalculate the size
m_wndToolBar.GetParentFrame()->RecalcLayout();
CDC* pDC = GetDC();
rectActualFrameSize.OffsetRect(-rectActualFrameSize.left,
-rectActualFrameSize.top);
m_wndToolBar.DrawBorders(pDC, rectActualFrameSize);
ReleaseDC(pDC);
}
把下列的数据成员加入 CMainFrame 类中并且在 CMainFrame's OnCreate成员函数设定他们初值:
int m_cyBorder;
int m_cxBorder;
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
m_cxBorder = GetSystemMetrics(SM_CXBORDER);
m_cyBorder = GetSystemMetrics(SM_CYBORDER);
.....
}
状态
这行为是藉着设计。
更多信息
为了要接受工具栏的定制特征 你一定将 CCS_ADJUSTABLE 风格设定为工具栏控制的特征,就象在这里显示:
m_wndToolBar.GetToolBarCtrl.()ModifyStyle;(0,CCS_ADJUSTABLE)
改变后,当定制对话框出现,最少有一个工具栏通知被处理。这个通知是TBN_QUERYINSERT,它能够在CMainFrame 类被处理,就象下面那样:
void CMainFrame::OnQueryInsert( NMHDR * pNotifyStruct, LRESULT * result )
{
*result = TRUE;
}
NMHDR 结构实际上是 NMTOOLBAR 通知结构。 应该被处理的另外一个通知是 TBN_GETBUTTONINFO 。 因为通知被送去,所以这很重要为那些可得被增加到工具栏的按纽发送请求按纽数据。 为了要适当地处理这一个通知, NMTOOLBAR 结构的 iItem 成员应该被比较到原先的 TBBUTTON 结构队列的索引 , 和处理的人应该将结构装满按纽数据而且设定result为TRUE。
叁考
对于关于该如何保持那定制会话框看得见的信息, 按文章在下面数看微软知识库的文章:
241850 PRB: Call to CToolBarCtrl::Customize() Does Not Keep the Customize Dialog Box Visible
MFC "Toolbar Topics" in the "Adding User Interface Features" section of the Visual C++ Programmer's Guide:
http://msdn.microsoft.com/library/en-us/vccore98/html/_core_toolbar_topics.asp
The Microsoft Platform SDK Documentation has extensive information on the ToolBar common control in its "User Interface Services" section under "Windows Common Controls":
http://msdn.microsoft.com/library/en-us/shellcc/shellcc/CommCtls/ToolBar/ToolBar.asp