C++实现橡皮筋拉伸线条类

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();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值