VC拖动条分割窗口模拟

来源:互联网 发布:数据挖掘入门书籍推荐 编辑:程序博客网 时间:2024/06/05 18:03

VC拖动条分割窗口模拟

1、介绍
 
一些常用的商用程序如迅雷、金山词霸2005,暴风影音等均有漂亮、清爽的界面,尤其是有一个漂亮的分隔条将整个窗口分割成若干区域,如下图,金山词霸2005,竖的蓝色的分割表,暴风简单的分割条将播放区和列表区分开。


照片描述:迅雷截图(水平分割窗口)


照片描述:暴风截图(垂直分割窗口)

    窗口的分割有很多实现的方法,如可以用MFCCSplitterWnd类实现窗口的分割,该方法对于SDI程序支持的非常好,对于对话框程序支持不太完善,用起来比较麻烦。本文采用鼠标消息:
             
鼠标移动WM_MOUSEMOVE,
    鼠标左键按下
WM_LBUTTONDWON,
    鼠标左键松开
WM_LBUTTONUP
并结合GDI绘图实现了窗口程序的分割,该方法适合任意的窗口,且分割条可以呈现任意图形(需结合GDI)。

2、原理

       首先观察一下怎么使用分隔条(词霸为例):

1)鼠标移动进入分隔条区域:此时鼠标光标切换,如果不离开该区域,鼠标光标不变,离开则复原光标。

2)鼠标在分隔条区域中按下

此时若左键按下:(鼠标光标可以改变),则开始绘制拖动的虚线框,若不松开,则移动鼠标,虚线框跟着移动,若松开,则分割位置重新定位

3)鼠标松开

若此时鼠标按住flag为真,则表明是在分隔条区域中按下后松开的(可能移动过),此时重新定位分隔条位置,并重绘分隔条以及相应改变的窗口。

为了实现该功能,需要控制变量和拖动区域相关变量:

l  是否在区域,是否鼠标左键按住

l  拖动区域:位置、宽度,虚线框位置及宽度(可以和拖动区域宽相等)

可以用两个BOOL变量m_bIsInBarRgn, m_bIsMouseDowning分别表示是否在区域中和是否左键按住。

 (a) BOOL m_bIsInBarRgn;

默认为FALSE

若第一次进入该区域[1][1],就设置为TRUE,离开该区域则为FALSE

鼠标在移动的过程中,反复检查鼠标点是否在区域中,

若在区域中,如果该值为TRUE,表示鼠标移动时,没有离开该区域,不用改变鼠标光标(已经换过了)

如果该值为FALSE,表示鼠标移动时,进入该区域,要改变鼠标图标

(b)   BOOL m_bIsMouseDowning;

默认值FALSE,表示鼠标松开,若TRUE:鼠标按住

如果鼠标按下,且鼠标点在拖动条区域中(此时m_bIsInBarRgn==TRUE),如果该值为FALSE,则变为TRUE

鼠标松开时(up),若该值为TRUE,则变为FALSE

(c)

int m_nPos; 

拖动条在客户区的位置

初始化给定一个值

鼠标按住区域拖动时,若松开,则改变该值(可以控制范围)

int m_nXPos;

拖动虚线框所在位置

初始化值和m_nPos值相同。

拖动时,抹去上次画的虚线框区域,画当前虚线框区域,改变该值为新的移动位置。

int m_nWidthDragBar;

拖动条窗口的宽,也是拖动虚线框的宽,如果在拖动条窗口画图像,则和图像的宽一样。

为了实现分隔条的绘制以及虚线框的绘制,需要提供对应的两个函数:

分隔条的绘制

void DrawDragBar(CDC* pDC);

void CDragBarDemoDlg::DrawDragBar(CDC* pDC)

{

       CRect rc;

       GetClientRect(rc);

 

//    CRect rcBar(m_nPos-1,0,m_nPos+m_nWidthDragBar,rc.Height());

//    CBrush brBar(RGB(100,100,255));

//    pDC->FrameRect(&rcBar,&brBar);

 

       CBitmap bmp;

       bmp.LoadBitmap(IDB_BAR);

       BITMAP sBmp;

       bmp.GetBitmap(&sBmp);

       CDC mdc;

       mdc.CreateCompatibleDC(pDC);

       CBitmap* oldBmp = mdc.SelectObject(&bmp);

       pDC->StretchBlt(m_nPos,0,sBmp.bmWidth,rc.Height(),&mdc,0,0,sBmp.bmWidth,sBmp.bmHeight,SRCCOPY);

       mdc.SelectObject(oldBmp);

       mdc.DeleteDC();

       bmp.DeleteObject();

}

虚线框的绘制

void DrawXBar(CDC* pDC,int nXNew);

void CDragBarDemoDlg::DrawXBar(CDC* pDC,int nXNew)

{

       int nXOld = m_nXPos;

       CRect rc;

       GetClientRect(rc);

       int c = 100;

       CPen pen(PS_SOLID,1,RGB(c,c,c));

       int nW = 3;

 

       CRect rcOld(nXOld,0,nXOld+nW,rc.Height());

       InvalidateRect(rcOld,FALSE);

       UpdateWindow();

 

       CRect rcNew(nXNew,0,nXNew+nW,rc.Height());

 

       CBrush* oldBr = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);

       CPen* oldPen = pDC->SelectObject(&pen);

       pDC->Rectangle(rcNew);

       pDC->SelectObject(oldPen);

       pDC->SelectObject(oldBr);

       //save now xbar pos

       m_nXPos = nXNew;

}

3、实现(以对话框为例)

1)在对话框类中添加对应变量和函数声明

       HCURSOR m_hCursorMouseOver;   //鼠标光标

       HCURSOR m_hCursorMouseDowning;

       int m_nPos;  //拖动条在客户区的位置

       int m_nXPos; //拖动框所在位置

       int m_nWidthDragBar;//拖动条窗口的宽

       void DrawDragBar(CDC* pDC);

       void DrawXBar(CDC* pDC,int nXNew);

       BOOL m_bIsInBarRgn;

BOOL m_bIsMouseDowning; //==FALSE,default,鼠标松开,==TRUE:鼠标按住

2)初始化

// TODO: Add extra initialization here

       CRect rc;

       GetClientRect(rc);

       m_nPos = 100; //rc.Width()/3;

       m_nXPos = m_nPos;

       m_nWidthDragBar = 5;  //和拖动条图像的宽度一样

 

       m_bIsInBarRgn = FALSE;

       m_bIsMouseDowning = FALSE;

 

       m_hCursorMouseOver = theApp.LoadCursor(IDC_MOUSE_OVER);

       m_hCursorMouseDowning = theApp.LoadCursor(IDC_MOUSE_DOWN);

3)绘制OnPaint函数

void CDragBarDemoDlg::OnPaint()

{

       if (IsIconic())

       {

              。。。。。。。。默认代码

       }

       else

       {//新添加代码

              CPaintDC dc(this);

              //以拖动条为边界,一分为二,左边区域填充为红色,右边填充为绿色

              CRect rc;

              GetClientRect(rc);

              CRect rcLeft(0,0,m_nPos,rc.Height());

              CRect rcRight(m_nPos+m_nWidthDragBar,0,rc.Width(),rc.Height());

                           

              CBrush brLeft(RGB(255,123,123));

              CBrush brRight(RGB(123,255,123));

              dc.FillRect(&rcLeft,&brLeft);

              dc.FillRect(&rcRight,&brRight);

 

//           int nMode = dc.SetBkMode(TRANSPARENT);

//           dc.DrawText("左边区域",&rcLeft,DT_SINGLELINE|DT_VCENTER|DT_CENTER);

//           dc.DrawText("右边区域",&rcRight,DT_SINGLELINE|DT_VCENTER|DT_CENTER);

//           dc.SetBkMode(nMode);

 

              DrawDragBar(&dc);

              CDialog::OnPaint();

       }

}

4)鼠标移动:添加WM_MOUSEMOVE消息处理函数

extern CDragBarDemoApp theApp;

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

{

       // TODO: Add your message handler code here and/or call default

       CRect rc;

       GetClientRect(rc);

       CRect rcBar(m_nPos,0,m_nPos+m_nWidthDragBar,rc.Height());

       CClientDC dc(this);

       if(rcBar.PtInRect(point)) //点在拖动条区域内

       {

              if(m_bIsInBarRgn == FALSE) //第一次进入该区域

              {

                     SetCursor(m_hCursorMouseOver);

                     SetCapture();

                     m_bIsInBarRgn = TRUE;

              }

              else

              {

                     if(m_bIsMouseDowning) //如果在该区域内移动,且按住了鼠标左键

                     {

                            //不用重画

                     }

              }

       }

       else//点不在该区域,检查是不是第一次离开该区域

       {

              if(m_bIsInBarRgn == TRUE) //第一次离开

              {

                     if (m_bIsMouseDowning) //按住鼠标左键离开

                     {

                            //限定移动的范围

                            if(point.x<50)

                            {

                                   point.x = 50;  

                                   CPoint pt(50,point.y);

                                   ClientToScreen(&pt);

                                   SetCursorPos(pt.x,pt.y);              //移动光标位置                  

                            }

                            if(point.x>180)

                            {

                                   point.x = 180;

                                   CPoint pt(180,point.y);

                                   ClientToScreen(&pt);

                                   SetCursorPos(pt.x,pt.y);

                            }

                            //----------------------------

                            DrawXBar(&dc,point.x);

                     }

                     else//真正的离开

                     {

                            ReleaseCapture();

                            SetCursor(theApp.LoadStandardCursor(IDC_ARROW));

                            m_bIsInBarRgn = FALSE;                         

                     }

              }

       }

       CDialog::OnMouseMove(nFlags, point);

}

5)鼠标左键按下  WM_LBUTTONDOWN

void CDragBarDemoDlg::OnLButtonDown(UINT nFlags, CPoint point)

{

       if(m_bIsInBarRgn)

       {

              CClientDC dc(this);

              //SetCursor(//m_hCursorMouseDowning);//设置鼠标按住时的光标

              //SetCapture();

              DrawXBar(&dc,point.x);

              m_bIsMouseDowning = TRUE;

       }

       CDialog::OnLButtonDown(nFlags, point);

}

(6)鼠标左键松开 WM_LBUTTONUP

void CDragBarDemoDlg::OnLButtonUp(UINT nFlags, CPoint point)

{

       if(m_bIsMouseDowning)

       {    

              m_bIsMouseDowning = FALSE;

              m_nPos = point.x;

              Invalidate();   

       }

       CDialog::OnLButtonUp(nFlags, point);

}