我在基于对话框的程序中使用了tree ctrl,我想单击并释放父项目时即展开子项目(MSN好像也是这怎么做的),我映射了消息如下:
void CMyTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{....
   if(...)
   { 展开子项目}}
但是只有双击时,或者单击tree ctrl的空白处(即不是项目处)释放时
才进入该函数,这是为什么啊?

解决方案 »

  1.   

    鼠标点击消息被CLICK事件截获。
      

  2.   

    那是不是也就是说当mouse单击item时,其点击消息已先被NM_CLICK事件截获,并被发往父窗口?那我要如何才能实现类似MSN的mouse leftbutton up于父项目时展开子项目呢?我想要的是作用于item上的鼠标释放事件?就没有办法获得吗?
      

  3.   

    如果你是想点击item时,获得鼠标响应的话,应该用类向导截获TVN_SELCHANGED消息
      

  4.   

    你的问题很有意思,当天我就去试了一下,结果部分如你所说,也就是当鼠标点在ITEM的LABEL,就是ITEM的文字部分时捕捉不到WM_LBUTTONUP消息,而点在空白处或者ITEM的BUTTON,就是显示 + 或者 - 的按钮上时,会发送WM_LBUTTONUP消息。这两天一直被这个问题所困扰,今天上午仔细研究了一下CTreeCtrl的鼠标消息,终于解决了楼主所要求的关于ITEM能象MSN那样的展开或者关闭动作。
    要实现这个功能,现在有两个问题要解决,一个是如何捕捉到WM_LBUTTONUP消息,二是当鼠标点ITEM的BUTTON时,该ITEM会立刻展开或者关闭,不会等到鼠标放开,因此要屏蔽掉这个缺省的展开动作,改成当鼠标放开时才展开或者关闭。经过跟踪鼠标消息,发现当鼠标点在ITEM的LABEL上,不拖动鼠标,然后放开,系统发送的消息是WM_LBUTTONDOWN和WM_MOUSEMOVE(注意,是WM_MOUSEMOVE,不是WM_LBUTTONUP,不知道是什么原因)。如果鼠标点在ITEM的LABEL上,然后拖动鼠标,最后释放鼠标,发送的是WM_LBUTTONDOWN, WM_MOUSEMOVE和WM_LBUTTONUP消息。因此我们需要处理这三个消息。从CTreeCtrl派生一个类,称为CMyTreeCtrl, 定义一个BOOL型的成员变量m_bLButtonDown和HTREEITEM型的变量m_hItemHitted用来记录鼠标左健是否已经被按下以及被点中的ITEM,并在构造函数中初始化为。构造函数和三个消息响应函数分别为
    CMyTreeCtrl::CMyTreeCtrl()
    {
        m_bLButtonDown = FALSE ;
        m_hItemHitted = NULL ;
    }
    void CMyTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point) 

        UINT flag ;
        HTREEITEM hItemHitted = HitTest( point, &flag ) ;
        if( flag & TVHT_ONITEMLABEL )
        {
            m_bLButtonDown = TRUE ;
            m_hItemHitted = hItemHitted ;
        }
        CTreeCtrl::OnLButtonDown(nFlags, point);
    }
    void CMyTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
    {
        m_bLButtonDown = FALSE ;
        UINT flag ;
        HTREEITEM hItemHitted = HitTest( point, &flag ) ;
        if( ( hItemHitted != NULL && flag&TVHT_ONITEMBUTTON ) ||
             ( hItemHitted == m_hItemHitted && flag&TVHT_ONITEMLABEL )  )
            Expand( hItemHitted, TVE_TOGGLE ) ;
        CTreeCtrl::OnLButtonUp(nFlags, point);
    }void CMyTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) 
    {
        UINT flag ;
        HTREEITEM hItemHitted = HitTest( point, &flag ) ;
        if( hItemHitted !=NULL && ( flag & TVHT_ONITEMLABEL ) )
        {
            if( m_bLButtonDown == TRUE && (!(nFlags & MK_LBUTTON )) )
            {
                Expand( hItemHitted, TVE_TOGGLE ) ;
                m_bLButtonDown = FALSE ;
            }
        }
        CTreeCtrl::OnMouseMove(nFlags, point);
    }
    最后屏蔽掉鼠标点击ITEM的BUTTON时的缺省动作,这时要处理NM_CLICK消息,如下
    void CMyTreeCtrl::OnClick(NMHDR* pNMHDR, LRESULT* pResult) 
    {
        CPoint pt ;
        UINT flag ;
        GetCursorPos( &pt ) ;
        ScreenToClient( &pt ) ;
        HTREEITEM hItemHitted = HitTest( pt, &flag ) ;
        if( hItemHitted != NULL && ( flag&TVHT_ONITEMBUTTON ) )
            *pResult = 1 ;  // 返回值为1,父窗口不处理这个消息
        else
            *pResult = 0;
    }消息映射为
    BEGIN_MESSAGE_MAP(CMyTreeCtrl, CTreeCtrl)
        //{{AFX_MSG_MAP(CMyTreeCtrl)
        ON_WM_LBUTTONUP()
        ON_WM_LBUTTONDOWN()
        ON_WM_MOUSEMOVE()
        ON_NOTIFY_REFLECT(NM_CLICK, OnClick)
        //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
      

  5.   

    呵呵,非常感谢A_Qiao() 如此详细的回答! 这个问题其实前些天我已经解决了,受了happyparrot的一些启发,虽然还是充满疑惑,不知道这究竟是为什么(所以还未结贴)?!
    我的方法如下:
    首先我把TreeCtrl的HAS_BUTTON 给关了(干净彻底),然后我把判断项目以及展开的代码都放进了
    CMyTreeCtrl::OnClick中,最后,我在CMyTreeCtrl::OnDBClick 中把      *pResult = 0;改成了    *pResult = 1 ,也实现了上述功能!
    疑惑的是:
    1、就是WM_LBUTTONDOWN好像是标准的WINDOWS消息吧,到了TreeCtrl中怎么就被封装进了NM_CLICK中了,像这样的消息“NM_CLICK”用spy++好象没有看到!
    2、只要我实现了CMyTreeCtrl::OnDBClick的消息映射,即使一个字也不改,那么我的父对话框的关于TreeCtrl资源的OnDBClick事件的消息映射函数如:CXXXDlg::OnDblclkTreectrl()
    就无法进入了,请问类似这种控件资源的消息路由究竟在MFC里是怎样的?它发给控件类本身的消息映射后就不再发给父窗体的消息映射了?dingsun2(白玉京)  你说的那个TVN_SELCHANGED事件 没有办法实现这样的情况(点击某一item展开,再点击该item要求收缩但TVN_SELCHANGED事件却未被触发!)
      

  6.   

    呵呵,控件各有不同。MFC不可能面面俱到的。