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