{A}
{S0}简介
有一个MFC的CToolBar类的错误,同时显示工具栏按钮的工具提示。当计算显示工具提示的是哪个按钮,工具栏按钮的位置移动1个像素的权利。因此,当鼠标光标指出的一个工具栏按钮的最左边的像素,其左侧的按钮的工具提示和状态栏提示的实际显示!
这是很容易重现此错误。创建一个MFC项目,无论是SDI或MDI,默认情况下,包括工具栏。保留所有其他项目的设置,其默认值。运行程序,并仔细将鼠标光标移动到"打开"工具栏按钮的最左边的像素。 CToolBar将显示"新建"按钮,在上面的图片显示,工具提示。这个错误是相当误导的。
一个众所周知的,基于MFC的软件件数受这个错误,包括间谍和。背景
挖成CToolBar源代码后,我发现这个bug的原因。当工具提示可能需要的工具栏,框架调用CToolBar::OnToolHitTest()来确定光标在哪个按钮。下面是这种方法的源代码,VC + + 6.0中复制。除非返回int类型改变成INT_PTR,几乎是不变的VC 8.0代码:int CToolBar::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
// check child windows first by calling CControlBar
int nHit = CControlBar::OnToolHitTest(point, pTI);
if (nHit != -1)
return nHit;
// now hit test against CToolBar buttons
CToolBar* pBar = (CToolBar*)this;
int nButtons = (int)pBar->DefWindowProc(TB_BUTTONCOUNT, 0, 0);
for (int i = 0; i < nButtons; i++)
{
CRect rect;
TBBUTTON button;
if (pBar->DefWindowProc(TB_GETITEMRECT, i, (LPARAM)&rect))
{
++rect.bottom; // Buggy line
++rect.right; // Buggy Line
if (rect.PtInRect(point) &&
pBar->DefWindowProc(TB_GETBUTTON, i, (LPARAM)&button) &&
!(button.fsStyle & TBSTYLE_SEP))
{
int nHit = GetItemID(i);
if (pTI != NULL && pTI->cbSize >= sizeof(AFX_OLDTOOLINFO))
{
pTI->hwnd = m_hWnd;
pTI->rect = rect;
pTI->uId = nHit;
pTI->lpszText = LPSTR_TEXTCALLBACK;
}
// found matching rect, return the ID of the button
return nHit != 0 ? nHit : -1;
}
}
}
return -1;
}
与缺陷所涉及的行说:"越野车线。"似乎没有理由增加1个像素,和MFC rect.bottom和rect.right,提供了这样做没有任何评论。这些行导致错误按钮的RECT要检索等错误的工具提示显示。 :(使用代码
修正错误,只需创建从CToolBar派生一个类,并覆盖了CToolBar::OnToolHitTest()方法。原来实行的CToolBar::OnToolHitTest()复制和注释掉两个越野车线。然后更换新的类CToolBar无处不在,它是在项目中使用。所附CFixedToolBar就是一个例子。
还有一些事情要做。如果你编译新的类,现在你会得到一个错误,说,AFX_OLDTOOLINFO是不确定的。它实际上是指在LT afximpl.hgt; TOOLINFO兼容版本,所以通过英寸,而不是提供的AFX_OLDTOOLINFO定义,是为了确保代码,简单地改变SIZEOF(AFX_OLDTOOLINFO)40,即AFX_OLDTOOLINFO结构的大小,是足够的。现在一切都OK。享受。 :)历史2007年7月16日 - 原始版本发表于