工具栏编程小结

FAQ1: 如何为工具栏添加CHEVRON

FAQ2: 如何实现工具栏按钮的拖拽

 

 

最近一直很忙,没空把新的知识沉淀、更好的消化。今天就把有关工具栏编程的知识汇总一下。那些教科书上有的东西就不写了,呵呵!

 

 

如何为工具栏添加CHEVRON

 

先说一下如何为工具栏添加CHEVRON,就是当工具栏按钮的长度超过了窗口能显示的长度时,在工具栏的右侧自动添加一小按钮,点击后可以把后面未显示的工具栏按钮以菜单的形式显示出来。点击此下载相关的代码

       实际上,这是个重组栏(Rebar)提供的功能,首先需为Rebar添加RBBS_USECHEVRON风格。请看下面的代码:

 

              REBARBANDINFO rbi;    

 

              memset( &rbi , 0 , sizeof(rbi) ) ;

 

              rbi.cbSize = sizeof( REBARBANDINFO ) ;

 

              rbi.fMask  = RBBIM_STYLE ;

 

              m_Rebar.GetBandInfo( index , &rbi ) ;

 

              rbi.fStyle |= ( RBBS_USECHEVRON | RBBS_BREAK ) ;  // RBBS_BREAK风格不是必需的!

 

              m_Rebar.SetBandInfo( index , &rbi ) ;            

 

      

 

或者可以通过另一种方式来添加RBBS_USECHEVRON风格:

 

       m_wndReBar.AddBar(&m_wndToolBar, NULL, NULL, RBBS_USECHEVRON )

 

      

 

       然后为ReBar指定正常显示的宽度,即当ReBar的实际长度超过这个宽度就自动出现CHEVRON

 

REBARBANDINFO rbi;    

 

              memset( &rbi , 0 , sizeof(rbi) ) ;

 

              rbi.cbSize = sizeof( REBARBANDINFO ) ;               

 

              rbi.fMask  = RBBIM_IDEALSIZE ;                    

 

              rbi.cxIdeal = GetToolbarWidth() ;

 

              m_Rebar.SetBandInfo( index , &rbi ) ;

 

 

 

       看看GetToolbarWidth()的代码:

 

              int nWidth = 0 ;

 

       int n = GetToolBarCtrl().GetButtonCount() ;

 

              for( int i = 0 ; i < n ; i ++ )

 

       {

 

                     CRect rtItem ;

 

              GetItemRect( i , &rtItem ) ;

 

                     nWidth += rtItem.Width() ;

 

       }

 

              return nWidth ;

 

 

 

       显然,这是个CToolbar派生类的成员函数!通过它来得到工具栏所有按钮的宽度的总和,这里包括了隐藏按钮的宽度,如果你用到了隐藏按钮,可能最终的效果和你期望的有一点出入。你还可以用CToolbarCtrl::GetMaxSize这个函数得到工具栏的宽度(此函数不计算隐藏按钮)。我不用GetMaxSize是有原因的,因为我做的工具栏长度是动态改变的,它不断的添加或删除某个按钮。我发现在这种情况下,GetMaxSize并不能得到准确的数据!使得在该出现CHEVRON时并不出现,或者在完全有足够长度显示按钮时也显示CHEVRON

 

       当然,你可以把两个SetBandInfo调用集中在一起,这样效率会更好。但我所做的工具栏的长度是在不断变化的,每次改变时都要重设cxIdeal,所以我把设置cxIdeal提取出来独立成一个函数。

 

       还有一个相关的风格:TBSTYLE_EX_HIDECLIPPEDBUTTONS。此风格是工具栏(不是ReBar)的扩展风格哦,通过CToolBarCtrl::SetExtendedStyle设置。设置了该风格后,工具栏上无法完全显示的按钮就会隐藏,并且加到CHEVRON的菜单中。

 

       最后声明一点,文中的代码与提供的例子并不是同一个代码!这个例子是我从网络上搜索来的。

 

 

 

 

 

如何实现工具栏按钮的拖拽

 

       再写一个关于工具栏按钮的拖拽。

 

有两个工具栏通知消息:TBN_BEGINDRAGTBN_ENDDRAG。关于这两个通知消息书上介绍的很少,网上也不多见!下面的代码介绍了如何处理该通知消息来实现工具栏按钮的拖拽:

 

 

 

TBN_BEGINDRAG通过消息的处理:

 

void CMyToolbar::OnTbnBeginDrag(NMHDR *pNMHDR, LRESULT *pResult)

 

{     

 

       LPNMTOOLBAR pNMTB = reinterpret_cast<LPNMTOOLBAR>(pNMHDR);          

 

       m_DragedID = pNMTB->iItem ;            // m_DragedID 保存了被拖的按钮ID

 

       m_bDragButton = TRUE ;                     // m_bDragButton BOOL变量,是个拖拽标志

 

       *pResult = 0;

 

}

 

 

 

注意:这里不用调用SetCapture哦!应该是默认的消息处理已经帮我们调用了SetCapture

 

 

 

TBN_ENDDRAG通知消息的处理:

 

void CMyToolbar::OnTbnEndDrag(NMHDR *pNMHDR, LRESULT *pResult)

 

{

 

       LPNMTOOLBAR pNMTB = reinterpret_cast<LPNMTOOLBAR>(pNMHDR);   

 

       if( m_bDragButton )

 

       {

 

              //

 

              // 放处理

 

              //

 

              CPoint point ;

 

              ::GetCursorPos( &point ) ;

 

              ScreenToClient( &point ) ;

 

             

 

              // 先检查鼠标是否在工具栏窗体内             

 

              CRect rc;

 

              GetClientRect( &rc ) ;

 

              if( rc.PtInRect( point ) )

 

              {

 

                     //

 

                     // 检查鼠标在哪个按钮之上,是否在搜索按钮上

 

                     //

 

                     int index = GetToolBarCtrl().HitTest( &point ) ;

 

                     UINT id = GetItemID( index ) ;

 

                     if( id >= 0 )

 

                     {                          

 

                            // 拖放对象不是同一个                         

 

                            if( id != m_DragedID )

 

                            {

 

                                   // 调换位置

 

                                   // ID=m_DragedID的按钮放在ID=id的前面(后面也可以,看你的需求)

 

                                  

 

                            }                          

 

                     }

 

             

 

              }

 

 

 

 

 

              m_DragedID = 0 ;

 

              m_bDragButton = FALSE ;           

 

              SetCursor( LoadCursor( NULL,IDC_ARROW ) ) ;

 

              InvalidateRect(NULL);

 

       }

 

       *pResult = 0;

 

}

 

 

 

 

 

最后是WM_MOUSEMOVE消息的处理,将拖的过程反馈给用户:

 

void CMyToolbar::OnMouseMove(UINT nFlags, CPoint point)

 

{

 

if ( m_bDragButton )

 

       {

 

              //

 

              // 先检查鼠标是否在工具栏窗体内

 

              //

 

              CRect rc;

 

              GetClientRect( &rc ) ;

 

              if( rc.PtInRect( point ) )

 

              {

 

                     //

 

                     // 检查鼠标在哪个按钮之上

 

                     //

 

                     int index = GetToolBarCtrl().HitTest( &point ) ;

 

                     UINT id = GetItemID( index ) ;

 

 

 

                     if( id >= 0 )

 

                     {

 

                            //

 

                            // 拖放对象不是同一个

 

                            //

 

                            if( id != m_DragedID )

 

                            {

 

                                   //

 

                                   // 在放目标按钮的前面画一条2象素的竖线,表示要将某个按钮拖到该按钮的前面!

 

                                   // 这里要怎么画,你可以凭自已的想象力,目的就是要让用户知道被拖的按钮即将被放在目标按钮的旁

 

                                   // 边,可以是前面或后面。可以画竖线,也可以画其它的。

 

                                   //

 

                                   CRect rtItem ;

 

                                   GetItemRect( index , &rtItem ) ;

 

                                   rtItem.right = rtItem.left + 2 ;

 

 

 

                                   CClientDC dc (this);

 

                                   dc.FillSolidRect( &rtItem , RGB(0,0,0) );

 

                            }

 

 

 

                            SetCursor( LoadCursor( ::AfxGetInstanceHandle() , (LPCTSTR)IDC_CURSOR_DROP_BUTTON )  ) ;

 

                     }

 

                    

 

                     else

 

{

 

                            SetCursor( LoadCursor( NULL,IDC_NO ) ) ;

 

                     }

 

                    

 

              }

 

              //

 

              // 不能放的区域

 

              //

 

              else

 

              {

 

                     SetCursor( LoadCursor( NULL,IDC_NO ) ) ;

 

              }

 

             

 

 

 

       }

 

 

 

       CToolBar::OnMouseMove(nFlags, point);

 

}

 

 

 

上面对三个消息的处理并不复杂,如果你曾经或常常为TREELIST控件写拖拽的代码,相信你很容易就可以理解。

 

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页