LineTracker.h
#pragma once
#include <windows.h>
class CLineTracker
{
int m_nPos;
int m_nMinPos;
int m_nMaxPos;
int m_nLineStart;
int m_nLineEnd;
int m_nLineWidth;
BOOL m_bVertical;
BOOL m_bTracking;
HWND m_hWnd;
COLORREF m_color;
public:
CLineTracker(BOOL bVertical = TRUE, int nWidth = 3, COLORREF color = RGB(128, 128, 128));
~CLineTracker();
BOOL Init(HWND hWnd, int nPos, int nMinPos = -1, int nMaxPos = -1, int nLineStart = -1, int nLineEnd = -1);
BOOL IsTracking() const
{
return m_bTracking;
}
void SetVertical(BOOL bVertical)
{
m_bVertical = bVertical;
}
BOOL IsVertical() const
{
return m_bVertical;
}
void SetColor(COLORREF color)
{
m_color = color;
}
COLORREF GetColor() const
{
return m_color;
}
void SetLineWidth(int nWidth)
{
m_nLineWidth = nWidth;
}
int GetLineWidth() const
{
return m_nLineWidth;
}
int GetLineStart() const
{
return m_nLineStart;
}
int GetLineEnd() const
{
return m_nLineEnd;
}
int GetMinPos() const
{
return m_nMinPos;
}
int GetMaxPos() const
{
return m_nMaxPos;
}
int GetPos() const
{
return m_nPos;
}
BOOL StartTrack(int nPos);
BOOL StopTrack();
BOOL Tracking(int nPos);
protected:
BOOL PosInLine(int nPos);
BOOL ShowCursor(int nPos);
BOOL GetRect(LPRECT lpRect) const;
BOOL Draw(int nPos, BOOL bDraw);
BOOL SetChildWndRedraw(BOOL bRedraw);
};
LineTracker.cpp
#include "LineTracker.h"
CLineTracker::CLineTracker(BOOL bVertical, int nWidth, COLORREF color)
: m_bVertical(bVertical)
, m_nLineWidth(nWidth)
, m_color(color)
{
m_nPos = 0;
m_nMinPos = -1;
m_nMaxPos = -1;
m_nLineStart = -1;
m_nLineEnd = -1;
m_hWnd = NULL;
m_bTracking = FALSE;
}
CLineTracker::~CLineTracker()
{
}
BOOL CLineTracker::Init(HWND hWnd, int nPos, int nMinPos, int nMaxPos, int nLineStart, int nLineEnd)
{
if (!IsWindow(hWnd))
{
ASSERT(FALSE);
return FALSE;
}
RECT rc = { 0 };
GetClientRect(hWnd, &rc);
DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
DWORD dwExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
BOOL bMenu = NULL != GetMenu(hWnd);
if (AdjustWindowRectEx(&rc, dwStyle, bMenu, dwExStyle))
{
if (-1 == nMinPos)
{
if (IsVertical())
{
nMinPos = rc.left;
}
else
{
nMinPos = rc.top;
}
}
if (-1 == nMaxPos)
{
if (IsVertical())
{
nMaxPos = rc.right;
}
else
{
nMaxPos = rc.bottom;
}
}
if (-1 == nLineStart)
{
if (IsVertical())
{
nLineStart = rc.top;
}
else
{
nLineStart = rc.left;
}
}
if (-1 == nLineEnd)
{
if (IsVertical())
{
nLineEnd = rc.bottom;
}
else
{
nLineEnd = rc.right;
}
}
}
if (nPos < nMinPos)
{
nMinPos = nPos;
}
if (nPos > nMaxPos)
{
nMaxPos = nPos;
}
m_hWnd = hWnd;
m_nPos = nPos;
m_nMinPos = nMinPos;
m_nMaxPos = nMaxPos;
m_nLineStart = nLineStart;
m_nLineEnd = nLineEnd;
return TRUE;
}
BOOL CLineTracker::GetRect(LPRECT lpRect) const
{
if (lpRect)
{
if (m_nLineWidth <= 0)
{
ASSERT(FALSE);
return FALSE;
}
if (m_nLineStart < 0)
{
ASSERT(FALSE);
return FALSE;
}
if (m_nLineEnd < 0)
{
ASSERT(FALSE);
return FALSE;
}
int hw = m_nLineWidth / 2;
RECT& rcLine = *lpRect;
if (IsVertical())
{
rcLine.left = m_nPos - hw;
rcLine.right = m_nPos + hw;
rcLine.top = m_nLineStart;
rcLine.bottom = m_nLineEnd;
}
else
{
rcLine.left = m_nLineStart;
rcLine.right = m_nLineEnd;
rcLine.top = m_nPos - hw;
rcLine.bottom = m_nPos + hw;
}
return TRUE;
}
return FALSE;
}
BOOL CLineTracker::PosInLine(int nPos)
{
int hw = m_nLineWidth / 2;
if (nPos >= m_nPos - hw && nPos <= m_nPos + hw)
{
return TRUE;
}
return FALSE;
}
BOOL CLineTracker::StartTrack(int nPos)
{
if (!m_bTracking)
{
if (PosInLine(nPos))
{
m_nPos = nPos;
ShowCursor(m_nPos);
if (Draw(m_nPos, FALSE))
{
m_bTracking = TRUE;
SetChildWndRedraw(FALSE);
SetCapture(m_hWnd);
return TRUE;
}
}
}
return FALSE;
}
BOOL CLineTracker::StopTrack()
{
if (m_bTracking)
{
if (Draw(m_nPos, FALSE))
{
m_bTracking = FALSE;
SetChildWndRedraw(TRUE);
ReleaseCapture();
return TRUE;
}
}
return FALSE;
}
BOOL CLineTracker::Tracking(int nPos)
{
ShowCursor(nPos);
if (m_bTracking)
{
return Draw(nPos, TRUE);
}
return FALSE;
}
BOOL CLineTracker::ShowCursor(int nPos)
{
if (PosInLine(nPos))
{
if (IsVertical())
{
SetCursor(LoadCursor(NULL, IDC_SIZEWE));
}
else
{
SetCursor(LoadCursor(NULL, IDC_SIZENS));
}
return TRUE;
}
return FALSE;
}
BOOL CLineTracker::Draw(int nPos, BOOL bDraw)
{
if (!IsWindow(m_hWnd))
{
ASSERT(FALSE);
return FALSE;
}
HDC hdc = GetDC(m_hWnd);
if (NULL == hdc)
{
return FALSE;
}
SelectObject(hdc, GetStockObject(NULL_BRUSH));
HPEN hNewPen = CreatePen(PS_SOLID, m_nLineWidth, m_color);
HPEN hOldPen = (HPEN)SelectObject(hdc, hNewPen);
SetROP2(hdc, R2_NOTXORPEN);
int hw = m_nLineWidth / 2;
int nNewPos = nPos;
if (nNewPos < m_nMinPos)
{
nNewPos = m_nMinPos;
}
if (nNewPos > m_nMaxPos)
{
nNewPos = m_nMaxPos;
}
if (IsVertical())
{
int xPos = m_nPos - hw;
MoveToEx(hdc, xPos, m_nLineStart, NULL);
LineTo(hdc, xPos, m_nLineEnd);
m_nPos = nNewPos;
if (bDraw)
{
xPos = m_nPos - hw;
MoveToEx(hdc, xPos, m_nLineStart, NULL);
LineTo(hdc, xPos, m_nLineEnd);
}
}
else
{
int yPos = m_nPos - hw;
MoveToEx(hdc, m_nLineStart, yPos, NULL);
LineTo(hdc, m_nLineEnd, yPos);
m_nPos = nNewPos;
if (bDraw)
{
yPos = m_nPos - hw;
MoveToEx(hdc, m_nLineStart, yPos, NULL);
LineTo(hdc, m_nLineEnd, yPos);
}
}
SelectObject(hdc, hOldPen);
DeleteObject(hNewPen);
ReleaseDC(m_hWnd, hdc);
return TRUE;
}
BOOL CLineTracker::SetChildWndRedraw(BOOL bRedraw)
{
if (!IsWindow(m_hWnd))
{
ASSERT(FALSE);
return FALSE;
}
HWND hChild = GetWindow(m_hWnd, GW_CHILD);
static const LPCTSTR sWndName = _T("SetChildWndRedraw");
static HANDLE shVisible = (HANDLE)1;
while (hChild)
{
BOOL hasProp = FALSE;
if (shVisible == GetProp(hChild, sWndName))
{
hasProp = TRUE;
}
if (IsWindowVisible(hChild) || hasProp)
{
if (hasProp)
{
SetProp(hChild, sWndName, NULL);
}
else
{
SetProp(hChild, sWndName, shVisible);
}
SendMessage(hChild, WM_SETREDRAW, bRedraw, 0);
if (bRedraw)
{
InvalidateRect(hChild, NULL, TRUE);
}
}
hChild = GetWindow(hChild, GW_HWNDNEXT);
}
return TRUE;
}
使用方法:
1. 定义 CLineTracker tacker;
2. 初始化
void OnSize(UINT nType, int cx, int cy)
{
//布局完成后初始化, nPos为橡皮条初始位置
tacker.init(m_hWnd, nPos, 100, 500);
}
3. 开始
void OnLButtonDown(UINT nFlags, CPoint point)
{
//垂直方向的橡皮条
if (tracker.IsVertical())
{
tracker.StartTrack(point.x);
}
else
{
tracker.StartTrack(point.y);
}
}
4. 移动中
void OnMouseMove(UINT nFlags, CPoint point)
{
//垂直方向的橡皮条
if (tracker.IsVertical())
{
tracker.Tracking(point.x);
}
else
{
tracker.Tracking(point.y);
}
}
5. 结束
void OnLButtonUp(UINT nFlags, CPoint point)
{
tracker.StopTrack();
}