情况是这样的!
我用勾子拦截了按钮的消息,主要目的是对按钮进行外观上绘制,如下:
case WM_PAINT:
{
pButton->OnPaint(hWnd);
break;
}
case WM_LBUTTONDOWN:
{
                        ::InvalidateRect(hWnd,NULL,true);
                        break;
                }
case WM_LBUTTONUP:
{
                       ::InvalidateRect(hWnd,NULL,true);
                     break;
}
通过上面代码,达到了绘制目的,可是在后来的测试中发现出现了问题,描述如下:
    当我把鼠标按住按钮时,鼠标不放开,然后再把鼠标移出按钮外部,当鼠标移刚好移出按钮外部时(事实上,如果我不在WM_LBUTTONDOWN加上InvalidateRect的话,在按下鼠标的时候外观就变了),发现按钮的外观变成了MFC默认的灰色绘制效果,再把鼠标移入按钮内部,按钮的外观还是MFC默认的灰色,直到我放开鼠标才会恢复我的自绘制效果。我想了很多办法来解决这个问题,如果,在case WM_MOUSEMOVE:内加上OnPaint()函数啦等等,最终都没办法解决;
    后来发现:原来MFC在WM_LBUTTONDOWN内对鼠标进行了捕获,直到WM_LBUTTONUP才释放,所以我在按下鼠标后,这中间的消息如WM_MOUSEMOVE都没能拦截到,被MFC做了默认的处理,所以我们看到,当鼠标在移动时,MFC做了它的灰色绘制处理,而我在WM_MOUSEMOVE所做的绘制都没能得到执行!
    既然MFC把这段时间的消息捕获了,我显得无能为力,没办法,我了照它的样,也来捕获鼠标,所以我在case WM_LBUTTONDOWN:也进行了如下的鼠捕获代码如下:case WM_LBUTTONDOWN:
{
  pButton->mPress=true;
  pButton->OnPaint(hWnd);
if (::GetCapture() == NULL)
{
SetCapture(hWnd);
ASSERT(hWnd == GetCapture());

AfxLockTempMaps();
for (;;)
{
MSG msg;
VERIFY(::GetMessage(&msg, NULL, 0, 0));

if (::GetCapture() != hWnd) break;

switch (msg.message)
{
case WM_LBUTTONUP:
{
pButton->mPress=false;
pButton->OnPaint(hWnd);
}
goto ExitLoop2;

case WM_KEYDOWN:
if (msg.wParam != VK_ESCAPE) 
break;

default:
DispatchMessage(&msg);
break;
}
}
ExitLoop2:
ReleaseCapture();
AfxUnlockTempMaps(FALSE);
}
经过以上处理发现,其内部
case WM_LBUTTONUP:
{
pButton->mPress=false;
pButton->OnPaint(hWnd);
}
这段代码并未得到执行!因为在按钮上按下鼠标再放开时,鼠标同样变成MFC默认绘制效果,且在放开鼠标后发现按钮还保持对鼠标的捕获,所以导致了对按扭的单击事件也无法得到执行!
我该怎么办?请高手们帮忙看看指点指点!

解决方案 »

  1.   

    用一个定时器与GetCursorPos来捕捉鼠标的位置,得到按钮的Rect在定时器里用PtInRect来判断点是否在按钮上
      

  2.   

    你可能没看清楚我的问题,我并不是无法判断鼠标位置,因为我已经注册了鼠标 TME_LEAVE | TME_HOVER 两个事件,能够很好的处理鼠标的位置问题。
      

  3.   

    是在这里面截取的么?BOOL PreTranslateMessage
      

  4.   

    ExitLoop2:
    ReleaseCapture();
    AfxUnlockTempMaps(FALSE);
    }
    经过以上处理发现,其内部
    case WM_LBUTTONUP:
    {
    pButton->mPress=false;
    pButton->OnPaint(hWnd);
    }
    这段代码并未得到执行!因为在按钮上按下鼠标再放开时,鼠标同样变成MFC默认绘制效果,且在放开鼠标后发现按钮还保持对鼠标的捕获,所以导致了对按扭的单击事件也无法得到执行!
    我该怎么办?请高手们帮忙看看指点指点!

    ////////////////////////////////////////////////
    我在放开鼠标时,会产生WM_LBUTTONUP消息,然后该消息应该会送到捕获鼠标的代码WM_LBUTTONUP内执行,也即最终会让程序运行到下面代码处:
    ExitLoop2:
    ReleaseCapture();
    AfxUnlockTempMaps(FALSE);
    释放鼠标捕获,可问题是,我放开鼠标后,并没有释放鼠标捕获,且导致鼠标的单击事件都无法得到执行。针对以上问题,我在想,MFC本身就在WM_LBUTTONDOWN内进行了鼠标捕获,而我也是在该消息内进行鼠标捕获,难道这样会有冲突?应该是我捕获鼠标后,那么MFC默认对鼠标的捕获就应该被释放了而不对会我的捕获产生干扰嘛!
      

  5.   

    按钮控件的很多消息都会重绘控件,不经过WM_PAINT消息。要自绘按钮应该给控件设置BS_OWNERDRAW风格,相应WM_DRAWITEM消息来处理。
      

  6.   

    我拦截的是按钮的消息,而不是按钮父窗口的消息,按钮本身只有一个DrawItem虚函数,没有WM_DRAWITEM这个消息,因为一开始我也拦截过,根本就拦截不到按钮的WM_DRAWITEM消息。
      

  7.   

    重载CButton类,处理WM_DRAWITEM消息
      

  8.   

    呵呵。。你从CButton源生个新类,重载相应的消息处理函数就行。
    如果你非要这样实现,建议你按最开始的方法做,只处理WM_PAINT,WM_LBUTTONDOWN,WM_LBUTTONUP消息,另外多处理一下WM_ERASBKGND消息,直接返回TRUE。应该就不会出现你所说的离开就变成默认按钮的情形了。
      

  9.   

    首先WM_MOUSEMOVE这个消息是不可靠的,又是鼠标没有移动时会有,而移动的时候又没有,而且你也不能保证鼠标在移除边框的那一瞬间恰好得到这个消息。此外CButton这个行为是遵守Windows的界面规范的,鼠标可以按下后移除按钮,使单击无效,但是在移除前要保持按下。为了保证单击这个事件和效果,所以MFC就对WM_LBUTTONDOWN做了处理。
    最好还是通过重载CButton,这也是比较标准的OOP方法。WM_DRAWITEM这个消息是虚拟的,背后有MFC的消息反射机制,你必须重载CButton后,才可以处理这个。而且原始的Windows编程中,Button之类是没有消息循环的,它的消息是父窗口处理的,也用不到鼠标捕获。你也你在父窗口里做的消息处理,注意处理反射消息,在父窗口绘制Button也是可能的。
      

  10.   

    谢谢楼上的,事实重载CButton来我已经实现了,只是重载在使用起来不太方便,使用时要对每一个CButton进行重新关连新的Button类!有没有什么办法一次性把窗口上所有的按钮都关连到新的Button类呢?
      

  11.   

    按钮要设置BS_OWNERDRAW风格才会给父窗口发WM_DRAWITEM消息。
    可以用FindWindowEx或EnumChildWindows遍历所有控件,根据类名来区分,逐一子类化。实际上只要把每个按钮的风格都改成BS_OWNERDRAW,然后在父窗口响应WM_DRAWITEM消息即可。