⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hxsplitterwnd.cpp

📁 类似 windows explorer的工具
💻 CPP
字号:
// HxSplitterWnd.cpp : implementation file
//

#include "stdafx.h"
#include "HxSplitterWnd.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CHxSplitterWnd

CHxSplitterWnd::CHxSplitterWnd()
{
    m_bInDragTestNow = FALSE;
    m_meDirection = MD_HORIZONTAL;
}

CHxSplitterWnd::~CHxSplitterWnd()
{
}


BEGIN_MESSAGE_MAP(CHxSplitterWnd, CWnd)
//{{AFX_MSG_MAP(CHxSplitterWnd)
ON_WM_SETCURSOR()
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_RBUTTONDOWN()
ON_WM_RBUTTONUP()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CHxSplitterWnd message handlers

BOOL CHxSplitterWnd::AddWindow(int nID, WindowSide nSide)
{
    // todo 应该保证ID不重复.
    m_vIDS.push_back(nID);
    m_vStyle.push_back(nSide);
    
    return TRUE;
}

MoveDirection CHxSplitterWnd::SetMoveDirection(MoveDirection nDirect)
{
    MoveDirection m_meOldDirection = m_meDirection;
    m_meDirection = nDirect;
    
    return m_meOldDirection;
}

BOOL CHxSplitterWnd::Create(CWnd* pParentWnd)
{
    DWORD dwStyle = WS_VISIBLE | WS_CHILDWINDOW | WS_OVERLAPPED;
    
    CREATESTRUCT cs;
    
    memset(&cs, 0, sizeof(cs));
    cs.lpszClass = AfxRegisterWndClass(CS_DBLCLKS,::LoadCursor(0,IDC_ARROW));
    cs.style = dwStyle;
    cs.hInstance = AfxGetInstanceHandle();
    cs.hwndParent = pParentWnd->GetSafeHwnd();
    return CWnd::Create(cs.lpszClass, cs.lpszName, cs.style,
        CRect(0,0,4,0), pParentWnd, 0);
    //return CWnd::Create("BaseBar", NULL, dwStyle, CRect(0,0,10,0), pParentWnd, nID);
}

// 计算是否移动某个窗口
// CRect 是屏幕坐标
// ptDiff 是移动偏移点
BOOL CHxSplitterWnd::CountNewRect(CRect &rc, int nIdx, CPoint ptDiff)
{
    CWnd* pWnd = GetParent()->GetDlgItem(m_vIDS[nIdx]);
    ASSERT(pWnd != NULL);
    
    // 首先得到 pWnd 在父窗口中的位置
    pWnd->GetWindowRect(&rc);
    GetParent()->ScreenToClient(&rc);
    
    // 父窗口窗口范围
    CRect rcParent;
    
    GetParent()->GetClientRect(&rcParent);
    
    // 计算出wnd的新位置
    // 左右移动
    switch (m_vStyle[nIdx])
    {
    case SIDE_LEFT:
        rc.left = 0;
        rc.right += ptDiff.x;
        break;
    case SIDE_RIGHT:
        rc.left += ptDiff.x;
        rc.right = rcParent.right;
        break;
    default:
        ASSERT(FALSE);
        break;
    }
    
    BOOL canmove = (rc.bottom>rc.top && rc.left<rc.right);
    return canmove;
    
}

// 执行实际的移动
// ptNewPos: 新点坐标
// ptDiff:   偏移坐标
void CHxSplitterWnd::MoveOneWindow(CPoint ptNewPos, CPoint ptDiff)
{
    if (!(m_meDirection & MD_HORIZONTAL))
    {
        ptDiff.x = 0;
    }
    if (!(m_meDirection & MD_VERTICAL))
    {
        ptDiff.y = 0;
    }
    
    // 拆分窗口的旧位置
    CRect rcMe;
    
    this->GetWindowRect(&rcMe);
    GetParent()->ScreenToClient(&rcMe); // 拆分窗口在父窗口中的位置
    
    // 拆分窗口的新位置
    int nNewLeft = rcMe.left + ptDiff.x;
    int nNewTop  = rcMe.top + ptDiff.y;
    
    BOOL canAll = TRUE; // 所有都能移动
    CRect rect;
    
    for(int i = 0; i < m_vIDS.size(); ++i)
    {
        if (!CountNewRect(rect,i,ptDiff))
        {
            canAll = FALSE;
        }
    }
    
    // 父窗口窗口范围
    CRect rcParent;
    
    GetParent()->GetClientRect(&rcParent);
    
    if(canAll && nNewLeft > 0 && nNewLeft < rcParent.right
        && nNewTop >= 0 && nNewTop < rcParent.bottom)
    {
        // 分别移动每个窗口
        for(int i = 0; i < m_vIDS.size(); i++)
        {
            CountNewRect(rect,i,ptDiff);
            CWnd *wnd = GetParent()->GetDlgItem(m_vIDS[i]);
            wnd->MoveWindow(&rect);
            //GetParent()->PostMessage(WM_MOVE_ZSPLITTER,0,(long)wnd->m_hWnd);
            //wnd->UpdateWindow();
        }
        // 移动拆分窗口到新位置
        SetWindowPos(NULL, nNewLeft, nNewTop, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
        this->Invalidate(); // 重绘拆分条

        m_pointDragStart = ptNewPos - ptDiff;
    }
    
}

BOOL CHxSplitterWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
    if (pWnd == this && nHitTest == HTCLIENT)
    {
        static int _afx_idcPrimaryLast = 0;
        static HCURSOR _afx_hcurLast = NULL;
        static HCURSOR  _afx_hcurDestroy = 0;
        int idcPrimary = 0;
        //idcPrimary = AFX_IDC_SMALLARROWS;
        
        if (m_meDirection == MD_HORIZONTAL)
        {
            idcPrimary = AFX_IDC_HSPLITBAR;
        }
        else if(m_meDirection == MD_VERTICAL)
        {
            idcPrimary = AFX_IDC_VSPLITBAR;
        }
        
        if (idcPrimary != 0)
        {
            HCURSOR hcurToDestroy = NULL;
            if (idcPrimary != _afx_idcPrimaryLast)
            {
                HINSTANCE hInst = AfxFindResourceHandle(MAKEINTRESOURCE(idcPrimary), RT_GROUP_CURSOR);
                
                // load in another cursor
                hcurToDestroy = _afx_hcurDestroy;
                
                // Note: If this LoadCursor call fails, it is likely that
                //  _AFX_NO_SPLITTER_RESOURCES is defined in your .RC file.
                // To correct the situation, remove the following line from your
                //  resource script:
                //      #define _AFX_NO_SPLITTER_RESOURCES
                // This should be done using the Resource.Set Includes... command.
                
                if ((_afx_hcurDestroy = _afx_hcurLast =
                    ::LoadCursor(hInst, MAKEINTRESOURCE(idcPrimary))) == NULL)
                {
                    TRACE0("Warning: Could not find splitter cursor - using system provided alternative.\n");
                    return CWnd::OnSetCursor(pWnd,nHitTest,message);
                }
                _afx_idcPrimaryLast = idcPrimary;
            }
            ASSERT(_afx_hcurLast != NULL);
            ::SetCursor(_afx_hcurLast);
            ASSERT(_afx_hcurLast != hcurToDestroy);
            if (hcurToDestroy != NULL)
                ::DestroyCursor(hcurToDestroy); // destroy after being set
        } // end if (idcPrimary != 0)

        return TRUE;
    }

    return CWnd::OnSetCursor(pWnd, nHitTest, message);
}

void CHxSplitterWnd::OnPaint() 
{
    CPaintDC dc(this); // device context for painting
    
    CRect rect;
    GetClientRect(&rect);

    //todo
    //dc.Draw3dRect(&rect, GetSysColor(COLOR_BTNSHADOW), GetSysColor(COLOR_BTNSHADOW));
    dc.DrawFrameControl(&rect,DFC_BUTTON,DFCS_BUTTONPUSH);
    //dc.FillSolidRect(&rect, COLOR_WINDOWFRAME);
    //rect.InflateRect(-2, -2);
    //dc.Draw3dRect(rect, COLOR_WINDOWFRAME, COLOR_BTNFACE);
    
    // Do not call CWnd::OnPaint() for painting messages
}

void CHxSplitterWnd::OnLButtonDown(UINT nFlags, CPoint point) 
{
    m_pointDragStart = point;
    m_bInDragTestNow = TRUE;
    SetCapture();
    
    CWnd::OnLButtonDown(nFlags, point);
}

void CHxSplitterWnd::OnLButtonUp(UINT nFlags, CPoint point) 
{
    ReleaseMouse();
    CWnd::OnLButtonUp(nFlags, point);
}

void CHxSplitterWnd::OnRButtonDown(UINT nFlags, CPoint point) 
{
    ReleaseMouse();
    CWnd::OnRButtonDown(nFlags, point);
}

void CHxSplitterWnd::OnRButtonUp(UINT nFlags, CPoint point) 
{
    ReleaseMouse();
    CWnd::OnRButtonUp(nFlags, point);
}

void CHxSplitterWnd::ReleaseMouse()
{
    if (m_bInDragTestNow)
    {                                     // drag was not initiated
        m_bInDragTestNow = FALSE;
        ReleaseCapture();
    }
}

void CHxSplitterWnd::OnMouseMove(UINT nFlags, CPoint point) 
{
    if (m_bInDragTestNow)
    {
        MoveOneWindow(point, point - m_pointDragStart);
    }
    else 
    {
        CWnd::OnMouseMove(nFlags, point);	
    }
}

// 初始化窗口位置
void CHxSplitterWnd::RelayWindows()
{
    CRect rcParent;
    
    // 父窗口窗口范围
    GetParent()->GetClientRect(&rcParent);
    if (rcParent.IsRectEmpty()) 
    {
        return;
    }
    
    CRect rcLeft;
    CRect rcRight;
    CWnd* pLeftWnd = GetSomeWnd(SIDE_LEFT);
    CWnd* pRightWnd = GetSomeWnd(SIDE_RIGHT);
    
    // 得到在父窗口中的位置
    // 1)Left
    pLeftWnd->GetWindowRect(&rcLeft);
    GetParent()->ScreenToClient(&rcLeft);
    rcLeft.left = 0;
    rcLeft.top = 0;
    rcLeft.bottom = rcParent.bottom;
    
    // 2)Me(拆分窗口)
    CRect rcMe;
    
    this->GetWindowRect(&rcMe);
    GetParent()->ScreenToClient(&rcMe); // 拆分窗口在父窗口中的位置
    const int nMeWidth = rcMe.Width(); // 拆分窗口宽度
    
    rcMe.left = rcLeft.right;
    rcMe.right = rcMe.left + nMeWidth;
    rcMe.top = 0;
    rcMe.bottom = rcParent.bottom;
    
    // 3)Right
    rcRight.left = rcMe.right;
    rcRight.right = rcParent.right;
    rcRight.top = 0;
    rcRight.bottom = rcParent.bottom;
    
    // 分别移动每个窗口
    pLeftWnd->MoveWindow(&rcLeft);
    this->MoveWindow(&rcMe);
    pRightWnd->MoveWindow(&rcRight);
    
    //wnd->UpdateWindow();        
}

CWnd* CHxSplitterWnd::GetSomeWnd(WindowSide nSide)
{
    for(int i = 0; i < m_vIDS.size(); ++i)
    {
        if (m_vStyle[i] == nSide)
        {
            CWnd* pWnd = GetParent()->GetDlgItem(m_vIDS[i]);
            ASSERT(pWnd != NULL);
            
            return pWnd;
        }
    }
    return NULL;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -