1. 程式人生 > >用Win32實現帶分割條(Splitter)的視窗

用Win32實現帶分割條(Splitter)的視窗

在MFC中藉助嚮導的幫助很容易就能建立一個帶有分隔條(Splitter)的視窗,但是在Win32中一切都沒有那麼容易,在這篇文章裡我帶領大家用Win32實現一個帶這種Splitter的視窗。

一個Splitter分隔條,能夠將一個視窗分成兩部分,在我們實際的編碼專案中,這分開的兩個視窗能實現各自的功能。但是這個Splitter又是什麼呢? 告訴大家,這個Splitter其實僅僅是兩個分開的視窗的sunken edge。

首先我們在當前視窗下建立兩個子視窗,分別是Edit和Static,這都是Win32內建的子視窗控制元件。這裡要說明一下的是,下面的程式碼中我使用了自己寫就的一個視窗類,一些訊息響應我用這個視窗類的虛擬函式實現了,為了完整起見,我在這裡將整個函式體都列了出來。我的函式命名和引數列表都是參考MFC的,如果對Windows訊息到虛擬函式的對映不是特別明白,可以參考一下MSDN。

void KWindow::OnCreate(CREATESTRUCT* pCST,HWND hwnd)
{
    m_hEdit = CreateWindowEx( WS_EX_CLIENTEDGE,
        _T("Edit"), NULL,  
        WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_MULTILINE,
        0, 0, 0, 0,
        hwnd, NULL,
        pCST->hInstance, NULL );
    chlASSERT(m_hEdit);

    m_hLabel =
CreateWindowEx( WS_EX_CLIENTEDGE,
        _T("Static"), NULL,  
        WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
        0, 0, 0, 0,
        hwnd, NULL,
        pCST->hInstance, NULL );   
    chlASSERT(m_hLabel);

    RECT rc;
    GetClientRect(hwnd,&rc);
    m_splitterPos = rc.right / 2;

    m_hCursor =
LoadCursor(NULL,MAKEINTRESOURCE(IDC_SIZEWE));
}

要說明的是:m_splitterPos是分隔條在水平方向的位置。Edit和Static視窗建立時的大小都是0,因此我們需要在WM_SIZE訊息中讓他們調整到合適的大小。

void KWindow::OnSize(UINT nType, int cx, int cy)
{
    MoveWindow(m_hEdit,0,0,m_splitterPos,cy,true);
    MoveWindow(m_hLabel,m_splitterPos,0,cx - m_splitterPos,cy,true);
}

此外我們還需要讓Edit和Static各自顯示一些文字。

void KWindow::OnDraw(HDC hdc)
{
    SetWindowText(m_hLabel,_T("這是一個Static控制元件"));
    SetWindowText(m_hEdit,_T("這是一個Edit控制元件"));
}

現在執行一下,分隔條是能看見了:

下面要做的是當滑鼠移到分隔條周圍時,能夠調整分隔條的位置,兩個子視窗的大小也隨之更改。首先我們在WM_LBUTTONDOWN訊息內設定一個標記,表示現在可以調整大小,並設定滑鼠的形狀。在WM_LBUTTONUP訊息內,調整Splitter位置的工作已經結束,因此將標記設定為不允許調整大小,並將滑鼠形狀設定為正常情況。而在WM_MOUSEMOVE訊息內,我們可以設定Splitter的位置。

void KWindow::OnMouseMove(UINT nFlags,POINT pos)
{
    if(nFlags == MK_LBUTTON && m_IsSplit)
    {
        RECT rc;
        GetClientRect(m_hwnd,&rc);
        m_splitterPos = pos.x;
        SendMessage(m_hwnd,WM_SIZE,NULL,MAKELPARAM(rc.right,rc.bottom));
    }
}

void KWindow::OnLButtonDown(UINT nFlags, POINT pos)
{

    if( (pos.x >= m_splitterPos - 10) && ( pos.x <= m_splitterPos + 10) )
    {
        m_IsSplit = true;
        SetCursor(m_hCursor);
        SetCapture(this->m_hwnd);
    }
}
void KWindow::OnLButtonUp(UINT nFlags, POINT pos)
{
    if(m_IsSplit)
    {
        m_IsSplit = false;
        ReleaseCapture();  
    }
}