📄 hxsplitterwnd.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 + -