自绘滚动条

head document

typedef enum {
	HORCSB_MCS_NO_CAPTURE,
	HORCSB_MCS_TRACE_DRAG
} HorMouseCaptureStateSB;

typedef enum {
	HORMS_NORMAL,
	HORMS_OVER,
	HORMS_CLICK
} HorScrollState;

class HorScrollBar
{
public:
	HorScrollBar(HWND, HWND);
	HorScrollBar() {};
	~HorScrollBar() {};
	void ShowHorScrollBar(BOOL);
	void SetHorScrollBar(CustomSBInfo*);
	void GetHorScrollBar(CustomSBInfo*);
	void SetChildWindowVector(vector<HWND>);
	HWND GetScrollBarHwnd();


private:
	static LRESULT CALLBACK HorScrollBarWndProc(HWND, UINT, WPARAM, LPARAM);
	static HorScrollBar* csb;
	HWND CreateCustomScrollBar(HWND);
	int CalHorScrollbarLen(const int&, const int&);
	int CalHorScrollbarTop(const int&, const int&);
	int CalHorScrollbarOffset(const int&, const int&, const int&, const int&);
	int CalHorScrollbarCurPos(const int&, const int&, const int&);
	//鼠标操作
	void CSBMouseMove(UINT xPos, UINT yPos, UINT uKey);
	void HorScrollBar::CSBMouseMove(UINT xPos, UINT yPos, RECT rc, POINT old, POINT newP, UINT uKey);
	void CSBMouseLButtonDown(UINT xPos, UINT yPos);
	void CSBMouseLButtonUp(UINT xPos, UINT yPos);

	HWND scrollBarHwnd;
	HWND parentHwnd;
	HWND controlHwnd;
	HorMouseCaptureStateSB esCapture;
	HorScrollState msState;

	//以下为滚动条的属性
	BOOL isVisible;
	int minPos;
	int maxPos;
	int curPos;
	int pageSize;
	int lastCurPose;
	//适配非控件类窗口
	vector<HWND> childWindowVector;
};

void SetHorScrollInTreeView(HWND hWndTV, HorScrollBar* csb);
void SetHorScrollInProgress(int allCount, int pageSize, HorScrollBar* csb);

cpp document

HorScrollBar* HorScrollBar::csb = NULL;

HorScrollBar::HorScrollBar(HWND parentHwnd, HWND controlHwnd)
{
	csb = this;
	CreateCustomScrollBar(parentHwnd);
	this->parentHwnd = parentHwnd;
	this->controlHwnd = controlHwnd;
}

//创建滚动条
HWND HorScrollBar::CreateCustomScrollBar(HWND parentHwnd)
{
	WNDCLASSEXW wcex;

	if (!GetClassInfoEx(GetMyModuleHandle(), TEXT("HORSCROLLBAR"), &wcex))
	{
		wcex.cbSize = sizeof(WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		wcex.lpfnWndProc = HorScrollBarWndProc;
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = GetMyModuleHandle();
		wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		wcex.hbrBackground = pTheContext->hBrush_Main;
		wcex.lpszMenuName = NULL;
		wcex.lpszClassName = TEXT("HORSCROLLBAR");
		wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

		if (RegisterClassEx(&wcex) == 0)
		{
			return FALSE;
		}
	}

	scrollBarHwnd = CreateWindow(TEXT("HORSCROLLBAR"), TEXT("HorCustomSB"), WS_CHILD | WS_VISIBLE,
		0, 0, 0, 0, parentHwnd, NULL, GetMyModuleHandle(), NULL);

	//刚创建默认隐藏
	ShowWindow(scrollBarHwnd, SW_HIDE);
	isVisible = FALSE;

	return scrollBarHwnd;
}

//滚动条的回调函数
LRESULT CALLBACK HorScrollBar::HorScrollBarWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static BOOL s_isTracking = FALSE;
	HorScrollBar* curCSB = (HorScrollBar*)GetWindowLong(hWnd, GWL_USERDATA);
	static POINT pt, pe;
	static RECT rt, re;
	switch (message)
	{
	case WM_CREATE:
	{
		SetWindowLong(hWnd, GWL_USERDATA, (LONG)csb);
		csb->esCapture = HORCSB_MCS_NO_CAPTURE;
		csb->msState = HORMS_NORMAL;
		break;
	}
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hDC = BeginPaint(hWnd, &ps);
		RECT rcScrollBar;
		GetWindowRect(hWnd, &rcScrollBar);
		RECT sbRect;
		SetRect(&sbRect, 0, 0, rcScrollBar.right - rcScrollBar.left, rcScrollBar.bottom - rcScrollBar.top);
		HBRUSH br = pTheContext->hBrush_Main;
		switch (curCSB->msState)
		{
		case HORMS_NORMAL:
		{
			break;
		}
		case HORMS_OVER:
		{
			br = pTheContext->hBrush_LightBlue;
			break;
		}
		case HORMS_CLICK:
		{
			br = pTheContext->hBrush_Blue;
			break;
		}
		}
		FillRect(hDC, &sbRect, br);
		//DeleteObject(br);

		EndPaint(hWnd, &ps);
		break;
	}

	case WM_PGMOUSEWHEEL:
	{
		CustomSBInfo csbi;
		curCSB->GetHorScrollBar(&csbi);
		int oldPos = csbi.curPos;

		if (GET_WHEEL_DELTA_WPARAM(wParam) <= 0)
		{
			csbi.curPos += 1;
		}
		else
		{
			csbi.curPos -= 1;
		}

		curCSB->SetHorScrollBar(&csbi);

		break;
	}
	case WM_MOUSEMOVE:
	{
		if (!s_isTracking)
		{
			TRACKMOUSEEVENT tme;
			tme.cbSize = sizeof(TRACKMOUSEEVENT);
			tme.dwFlags = TME_LEAVE | TME_HOVER;
			tme.hwndTrack = hWnd;
			tme.dwHoverTime = HOVER_DEFAULT;
			s_isTracking = TrackMouseEvent(&tme);
		}
		GetCursorPos(&pe);     // 获取光标指针的新位置     
		curCSB->CSBMouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), re, pt, pe, wParam);
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	}
	case WM_MOUSELEAVE:
	{
		s_isTracking = FALSE;
		curCSB->msState = HORMS_NORMAL;
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	}
	case WM_MOUSEHOVER:
	{
		curCSB->msState = HORMS_OVER;
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	}
	case WM_LBUTTONDOWN:
	{
		curCSB->CSBMouseLButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
		GetCursorPos(&pt);      // 获取鼠标光标指针当前位置      
		GetWindowRect(hWnd, &rt);  // 获取窗口位置与大小
		RECT rcStatic;
		GetWindowRect(curCSB->parentHwnd, &rcStatic);

		re.left = rt.left - rcStatic.left - SCROLLBAR_MARGIN;
		re.right = rt.right - rt.left;    
		re.top = rt.top - rcStatic.top;
		re.bottom = re.top + (rt.bottom - rt.top);
		
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	}
	case WM_LBUTTONUP:
	{
		curCSB->CSBMouseLButtonUp(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	}
	case WM_SETHORSCROLLINFO:
	{
		ShowScrollBar(curCSB->controlHwnd, SB_HORZ, FALSE);
		if (wParam)
		{
			curCSB->SetHorScrollBar((CustomSBInfo*)lParam);
			curCSB->ShowHorScrollBar(TRUE);
		}
		else
		{
			curCSB->ShowHorScrollBar(FALSE);
		}
		break;
	}
	case WM_TREEVIEWSCROLL:
	{
		WCHAR szBuffer[MAX_LOADSTRING];
		//先找到第一个显示的项目
		HTREEITEM hItem = TreeView_GetRoot(curCSB->controlHwnd);
		for (int i = 0; i < curCSB->curPos; ++i)
		{
			hItem = TreeView_GetNextVisible(curCSB->controlHwnd, hItem);
		}
		//使当前项目作为第一个显示的项目
		TreeView_SelectSetFirstVisible(curCSB->controlHwnd, hItem);
		break;
	}
	case WM_PROGRESSSCROLL:
	{
		HWND childHwnd = GetWindow(curCSB->controlHwnd, GW_CHILD);
		while (childHwnd != NULL)
		{
			ShowWindow(childHwnd, SW_HIDE);
			childHwnd = GetWindow(childHwnd, GW_HWNDNEXT);
		}

		HDWP multiHwnd2 = BeginDeferWindowPos(curCSB->childWindowVector.size());
		for (int i = curCSB->curPos; i < curCSB->childWindowVector.size(); i++)
		{
			multiHwnd2 = DeferWindowPos(multiHwnd2, curCSB->childWindowVector[i], HWND_TOP, 5, 5 + (i - curCSB->curPos) * (PROGRESSHEIGHT + 5), PROGRESSWIDTH, PROGRESSHEIGHT, SWP_SHOWWINDOW);
		}
		EndDeferWindowPos(multiHwnd2);
		break;
	}
	case WM_LISTVIEWHORSCROLL:
	{
		//0112秦林啸
		CustomSBInfo HorListCsbi;
		HorListCsbi.curPos = curCSB->curPos;
		HorListCsbi.minPos = curCSB->minPos;
		HorListCsbi.maxPos = curCSB->maxPos;
		HorListCsbi.pageSize = curCSB->pageSize;
		SendMessage(curCSB->controlHwnd, WM_LISTVIEWHORSCROLL, NULL, (LPARAM)&HorListCsbi);

		break;
	}
	
	
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;

}

void HorScrollBar::SetChildWindowVector(vector<HWND> childVector)
{
	childWindowVector.clear();
	childWindowVector = childVector;
}

//设置滚动条的基本属性
void HorScrollBar::SetHorScrollBar(CustomSBInfo* cInfo)
{
	lastCurPose = curPos;
	minPos = cInfo->minPos;
	maxPos = cInfo->maxPos;
	curPos = cInfo->curPos;
	pageSize = cInfo->pageSize;

	if (curPos > maxPos - pageSize)
		curPos = maxPos - pageSize;
	else if (curPos < 0)
		curPos = 0;

	RECT rcParent;
	GetWindowRect(parentHwnd, &rcParent);

	int x = CalHorScrollbarTop(curPos, maxPos);
	int y = SCROLLBAR_MARGIN;
	int width = CalHorScrollbarLen(pageSize, maxPos);
	if (isVisible)
	{
		SetWindowPos(scrollBarHwnd, HWND_TOP, x + SCROLLBAR_MARGIN, y ,  width, SCROLLBAR_WIDTH,SWP_SHOWWINDOW);

		LPTSTR controlClassName = (wchar_t*)calloc(63 + 1, sizeof(wchar_t));
		int test = GetClassName(controlHwnd, controlClassName, 64);
		 if (wcscmp(controlClassName, TEXT("UI_DataJudgeList")) == 0)
		{
			SendMessage(scrollBarHwnd, WM_LISTVIEWHORSCROLL, 0, 0);
			HWND ruleHwnd = GetParent(parentHwnd);//评判窗口句柄
			RECT rcRule, rcRuleScroll;
			GetWindowRect(ruleHwnd, &rcRule);
			GetWindowRect(parentHwnd, &rcRuleScroll);//装载滚动条的static
			RECT rcUpdateRect;

			rcUpdateRect.left = rcRuleScroll.left - rcRule.left;
			rcUpdateRect.right = rcUpdateRect.left + (rcRuleScroll.right - rcRuleScroll.left);
			rcUpdateRect.top = rcRuleScroll.top - rcRule.top;
			rcUpdateRect.bottom = rcUpdateRect.top + (rcRuleScroll.bottom - rcRuleScroll.top);
			InvalidateRect(ruleHwnd, &rcUpdateRect, TRUE);
		}
	}
	else
	{
		SetWindowPos(scrollBarHwnd, HWND_TOP, x + SCROLLBAR_MARGIN, y ,  width, SCROLLBAR_WIDTH, SWP_HIDEWINDOW);
	}
}

//获取滚动条的基本属性
void HorScrollBar::GetHorScrollBar(CustomSBInfo* cInfo)
{
	cInfo->minPos = minPos;
	cInfo->maxPos = maxPos;
	cInfo->curPos = curPos;
	cInfo->pageSize = pageSize;
}

//是否显示滚动条
void HorScrollBar::ShowHorScrollBar(BOOL state)
{
	if (state && maxPos > pageSize)
	{
		ShowWindow(scrollBarHwnd, SW_SHOW);
		isVisible = TRUE;
	}
	else
	{
		ShowWindow(scrollBarHwnd, SW_HIDE);
		isVisible = FALSE;
	}
}

/*
* 计算水平滚动条的宽度
* @pageSize: 当前页面大小
* @maxPos: pos最大值
* @返回值: 滚动条的宽度
*/
int HorScrollBar::CalHorScrollbarLen(const int& pageSize, const int& maxPos)
{
	if (pageSize >= maxPos)
		return 0;

	RECT rcParent;
	GetWindowRect(parentHwnd, &rcParent);
	int widthParent = rcParent.right - rcParent.left - 2 * SCROLLBAR_MARGIN;//约为200
	return (int)((float)(widthParent * pageSize) / (float)maxPos);
}


/*
* 计算水平滚动条的起始位置
* @pageSize: 当前页面大小
* @curPos: 当前页面位置
* @maxPos: pos最大值
* @返回值: 滚动条的起始位置
*/
int HorScrollBar::CalHorScrollbarTop(const int& curPos, const int& maxPos)
{
	if (pageSize >= maxPos)
		return 0;

	RECT rcParent;
	GetWindowRect(parentHwnd, &rcParent);
	int widthParent = rcParent.right - rcParent.left - 2 * SCROLLBAR_MARGIN;
	return (int)((float)(widthParent * curPos) / (float)maxPos);
}

int HorScrollBar::CalHorScrollbarCurPos(const int& y, const int& maxPos, const int& pageSize)
{
	RECT rcParent;
	GetWindowRect(parentHwnd, &rcParent);
	int widthParent = rcParent.right - rcParent.left - 2 * SCROLLBAR_MARGIN;
	float perHeight = widthParent / (float)maxPos;
	return round(y / perHeight);
}

int HorScrollBar::CalHorScrollbarOffset(const int& curPos, const int& pageSize, const int& maxPos, const int& yOffset)
{
	if (pageSize >= maxPos)
		return 0;

	RECT rcParent;
	GetWindowRect(parentHwnd, &rcParent);
	int widthParent = rcParent.right - rcParent.left - 2 * SCROLLBAR_MARGIN;
	float len = ((float)(widthParent / (float)maxPos));
	int offsetPos = (int)(yOffset / len);

	return curPos + offsetPos;
}



HWND HorScrollBar::GetScrollBarHwnd()
{
	return scrollBarHwnd;
}


void HorScrollBar::CSBMouseMove(UINT xPos, UINT yPos, RECT rc, POINT old, POINT newP, UINT uKey)
{
	POINT ptMouse;
	ptMouse.x = xPos;
	ptMouse.y = yPos;
	msState = HORMS_OVER;

	if (uKey & MK_LBUTTON)
	{
		HorMouseCaptureStateSB curCapture = esCapture;
		switch (curCapture)
		{
		case HORCSB_MCS_TRACE_DRAG:
		{
			RECT re;
			//re.top = rc.top + (newP.y - old.y); // 窗口新的垂直位置    
			re.left = rc.left + (newP.x - old.x); // 窗口新的水平位置    

			POINT newCursor = ptMouse;
			CustomSBInfo csbi;
			GetHorScrollBar(&csbi);
			int oldPos = csbi.curPos;
			int newPos = CalHorScrollbarCurPos(re.left, csbi.maxPos, csbi.pageSize);

			if (oldPos != newPos)
			{
				csbi.curPos = newPos;
				SetHorScrollBar(&csbi);
			}
			msState = HORMS_CLICK;
			break;
		}

		default:
			msState = HORMS_OVER;
			break;
		}
	}
	else
	{
		msState = HORMS_OVER;
	}
}

void HorScrollBar::CSBMouseLButtonDown(UINT xPos, UINT yPos)
{
	POINT ptMouse;
	ptMouse.x = xPos;
	ptMouse.y = yPos;

	POINT pt = ptMouse;
	ClientToScreen(scrollBarHwnd, &pt);
	if (DragDetect(scrollBarHwnd, pt))
	{
		esCapture = HORCSB_MCS_TRACE_DRAG;
		msState = HORMS_CLICK;
		SetCapture(scrollBarHwnd);
	}
}

void HorScrollBar::CSBMouseLButtonUp(UINT xPos, UINT yPos)
{
	if (esCapture != HORCSB_MCS_NO_CAPTURE)
	{
		ReleaseCapture();

		POINT ptMouse;
		ptMouse.x = xPos;
		ptMouse.y = yPos;

		msState = HORMS_OVER;

		esCapture = HORCSB_MCS_NO_CAPTURE;
	}
}

void SetHorScrollInTreeView(HWND hWndTV, HorScrollBar* csb)
{
	//设置滚动条属性消息
	int allCount = TreeView_GetCount(hWndTV);
	int pageSize = TreeView_GetVisibleCount(hWndTV);
	HTREEITEM hItem = TreeView_GetRoot(hWndTV);
	int visibleCount = 0;
	while (hItem != NULL)
	{
		visibleCount++;
		hItem = TreeView_GetNextVisible(hWndTV, hItem);
	}

	if (allCount > pageSize)
	{
		if (visibleCount > pageSize)
		{
			CustomSBInfo csbi;
			csb->GetHorScrollBar(&csbi);
			csbi.maxPos = visibleCount;
			csbi.pageSize = pageSize;
			SendMessage(csb->GetScrollBarHwnd(), WM_SETSCROLLINFO, TRUE, (LPARAM)&csbi);
		}
		else
		{
			CustomSBInfo csbi;
			csb->GetHorScrollBar(&csbi);
			csbi.maxPos = visibleCount;
			csbi.pageSize = pageSize;
			SendMessage(csb->GetScrollBarHwnd(), WM_SETSCROLLINFO, FALSE, (LPARAM)&csbi);
		}
	}
	else
	{
		CustomSBInfo csbi;
		csb->GetHorScrollBar(&csbi);
		csbi.maxPos = allCount;
		csbi.pageSize = pageSize;
		SendMessage(csb->GetScrollBarHwnd(), WM_SETSCROLLINFO, FALSE, (LPARAM)&csbi);
	}
}

void SetHorScrollInProgress(int allCount, int pageSize, HorScrollBar* csb)
{
	//设置滚动条属性消息
	if (allCount > pageSize)
	{
		CustomSBInfo horcsbi;
		csb->GetHorScrollBar(&horcsbi);
		horcsbi.maxPos = allCount;
		horcsbi.pageSize = pageSize;
		SendMessage(csb->GetScrollBarHwnd(), WM_SETHORSCROLLINFO, TRUE, (LPARAM)&horcsbi);
	}
	else
	{
		CustomSBInfo horcsbi;
		csb->GetHorScrollBar(&horcsbi);
		horcsbi.maxPos = allCount;
		horcsbi.pageSize = pageSize;
		SendMessage(csb->GetScrollBarHwnd(), WM_SETHORSCROLLINFO, FALSE, (LPARAM)&horcsbi);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值