type tcustomscrollcontrol = class(TCustomControl) {** @explan(说明)带滚动条的窗口类 %% **} uses utslvclmemstruct; {** @explan(说明) 带滚动条的自绘制窗口 %% **} private FLocalX;//水平基准 FLocalXold; FLocalY;//垂直基准 FLocalYold; FSI; //滚动条结构 FAutoScroll; //自动滚动条 FThumbTrack; //thunmtrack FWhileStep ;//滚动步长 function SetAutoScroll(v); begin if(v in array(0,1,2,3))and v <> FAutoScroll then begin FAutoScroll := v; InitialScroll(); end end function SetWhileStep(v); begin if not(v>=1) then return ; nv := integer(v); if FWhileStep=nv then return ; FWhileStep := nv; end protected function GetXScrollDelta();virtual; //x间隔 begin {** @explan(说明) 获得x间隔 %% **} return 10; end function GetYScrollDelta();virtual; //y 间隔 begin {** @explan(说明) 获得y间隔 %% **} return 10; end function GetClientXCapacity();virtual; //宽度容量 begin {** @explan(说明) 客户区x容量 %% **} return 0; end function GetClientYCapacity();virtual; //高度容量 begin {** @explan(说明) 客户区y容量 %% **} return 0; //integer((yClient) / FDeltaY); end function GetClientXCount();virtual; //宽度间隔 begin {** @explan(说明) 客户区x数量 %% **} return 0; end function GetClientYCount();virtual; //高度项 begin {** @explan(说明) 客户区y数量 %% **} return 0; end function PositionChanged();virtual; //基准点改变 begin {** @explan(说明) 基准点改变回调 %% **} end function GetDeltaXpos();virtual; //水平变化 begin r := FLocalX-FLocalXold; FLocalXold := FLocalX; return r; end function GetDeltaYpos();virtual; //垂直变化 begin r := FLocalY-FLocalYold; FLocalYold := FLocalY; return r; end function GetXPos();virtual; begin return FLocalX; end function GetYPos();virtual; begin return FLocalY; end function SetXpos(x);virtual; begin nx := integer(x); if not HandleAllocated()then return FLocalX := nx; if nx <> FLocalX then begin hwnd := Handle; FSI.fMask := SIF_POS; //SIF_ALL; _wapi.GetScrollInfo(hwnd,SB_HORZ,FSI._getptr_); ypos := FSI.nPos; hwnd := Handle; FSI.fMask := SIF_POS; FSI.nPos := nx; _wapi.SetScrollInfo(hwnd,SB_HORZ,FSI._getptr_,TRUE); // 获得滚动条滑块的位置,由于窗口调整,它可能不是同一个值 _wapi.GetScrollInfo(hwnd,SB_HORZ,FSI._getptr_); if FSI.nPos <> ypos then begin FLocalXold := FLocalX; FLocalX := FSI.nPos; PositionChanged(); end end end function SetYpos(y);virtual; begin nx := integer(y); if not HandleAllocated()then return FLocalY := nx; if nx <> FLocalY then begin hwnd := Handle; FSI.fMask := SIF_POS; //SIF_ALL; _wapi.GetScrollInfo(hwnd,SB_VERT,FSI._getptr_); ypos := FSI.nPos; FSI.nPos := nx; FSI.fMask := SIF_POS; _wapi.SetScrollInfo(hwnd,SB_VERT,FSI._getptr_,TRUE); // 获得滚动条滑块的位置,由于窗口调整,它可能不是同一个值 _wapi.GetScrollInfo(hwnd,SB_VERT,FSI._getptr_); if FSI.nPos <> ypos then begin FLocalYold := FLocalY; FLocalY := FSI.nPos; PositionChanged(); end end end function InitialScroll();virtual; begin if not HandleAllocated()then return; hwnd := Handle; // 设置垂直滚动条范围和页面大小(设置页面大小将决定滑块的粗细) FSI.fMask := SIF_POS .| SIF_RANGE .| SIF_PAGE; FSI.nMin := 0; FSI.nPos := FLocalY; //20200709 FSI.nMax :=(FAutoScroll .& 1)?(GetClientYCount()):0; FSI.nPage := GetClientYCapacity(); _wapi.SetScrollInfo(hwnd,SB_VERT,FSI._getptr_,true); {if FSI.nMax>FSI.nPage then begin FLocalYold := FLocalY; FLocalY := 0; end else begin } FSI.fMask := SIF_POS; _wapi.GetScrollInfo(hwnd,SB_VERT,FSI._getptr_); FLocalYold := FLocalY; FLocalY := FSI.nPos; //end // 设置水平滚动条范围和页面大小(设置页面大小将决定滑块的粗细) FSI.cbSize := FSI._size_; FSI.fMask := SIF_RANGE .| SIF_PAGE .| SIF_POS; FSI.nMin := 0; FSI.nPos := FLocalX; FSI.nMax :=(FAutoScroll .& 2)?(GetClientXCount()):0; FSI.nPage := GetClientXCapacity(); _wapi.SetScrollInfo(hwnd,SB_HORZ,FSI._getptr_,TRUE); {if FSI.nMax>FSI.nPage then begin FLocalXold := FLocalX; FLocalX := 0; end else begin } FSI.fMask := SIF_POS; _wapi.GetScrollInfo(hwnd,SB_HORZ,FSI._getptr_); FLocalXold := FLocalX; FLocalX := FSI.nPos; //end PositionChanged(); end function DoVScroll(o,e);override; begin // 获得垂直滚动条的所有信息 if csDesigning in ComponentState then return; FSI.fMask := SIF_ALL; hwnd := e.hwnd; _wapi.GetScrollInfo(hwnd,SB_VERT,FSI._getptr_); // 保存当前滑块位置,迟些进行比较 yPos := FSI.nPos; case e.lowparam of // 用户点击键盘 Home 按键 SB_TOP: begin FSI.nPos := FSI.nMin; end // 用户点击键盘 End 按键 SB_BOTTOM: begin FSI.nPos := FSI.nMax; end // 用户点击滚动条上边的三角形 SB_LINEUP: begin FSI.nPos -= 1; end // 用户点击滚动条下边的三角形 SB_LINEDOWN: begin FSI.nPos += 1; end // 用户点击滑块上边的滚动条轴 SB_PAGEUP: begin //return ; FSI.nPos -= FSI.nPage; end // 用户点击滑块下边的滚动条轴 SB_PAGEDOWN: begin //return ; FSI.nPos += FSI.nPage; end // 用户拖动滚动条 SB_THUMBTRACK: begin if FThumbTrack then begin FSI.nPos := FSI.nTrackPos; end end SB_THUMBPOSITION: begin FSI.nPos := FSI.nTrackPos; end end // 设置滚动条滑块的新位置 if FSI.nPos=yPos then return; return SetYpos(FSI.nPos); FSI.fMask := SIF_POS; _wapi.SetScrollInfo(hwnd,SB_VERT,FSI._getptr_,TRUE); // 获得滚动条滑块的位置,由于窗口调整,它可能不是同一个值 _wapi.GetScrollInfo(hwnd,SB_VERT,FSI._getptr_); // 与此前的保存的值进行比较,如果不同则滚动窗口 FLocalY := FSI.nPos; if(FSI.nPos <> yPos)then begin PositionChanged(); end return 0; end function DoHScroll(o,e);override; begin if csDesigning in ComponentState then return; FSI.fMask := SIF_ALL; _wapi.GetScrollInfo(e.hwnd,SB_HORZ,FSI._getptr_); // 保存当前滑块位置,迟些进行比较 xPos := FSI.nPos; case e.lowparam of // 用户点击滚动条左边的三角形 SB_LEFT: begin FSI.nPos := FSI.nMin; end SB_RIGHT: begin FSI.nPos := FSI.nMax; end SB_LINELEFT: begin FSI.nPos -= 1; end // 用户点击滚动条右边的三角形 SB_LINERIGHT: begin FSI.nPos += 1; end // 用户点击滑块左边的滚动条轴 SB_PAGELEFT: begin FSI.nPos -= FSI.nPage; end // 用户点击滑块右边的滚动条轴 SB_PAGERIGHT: begin FSI.nPos += FSI.nPage; end // 用户拖动滚动条 SB_THUMBTRACK: begin if FThumbTrack then begin FSI.nPos := FSI.nTrackPos; end end SB_THUMBPOSITION: begin //return ; FSI.nPos := FSI.nTrackPos; end end; if FSI.nPos=xPos then return; return SetXpos(FSI.nPos); // 设置滚动条滑块的新位置 FSI.fMask := SIF_POS; _wapi.SetScrollInfo(e.hwnd,SB_HORZ,FSI._getptr_,TRUE); // 获得滚动条滑块的位置,由于窗口调整,它可能不是同一个值 _wapi.GetScrollInfo(e.hwnd,SB_HORZ,FSI._getptr_); // 与此前的保存的值进行比较,如果不同则滚动窗口 FLocalX := FLocalX; FLocalX := FSI.nPos; if(FSI.nPos <> xPos)then begin PositionChanged(); end end function DoMouseWheel(o,e);override; begin if csDesigning in ComponentState then return; hwnd := self.Handle; FSI.fMask := SIF_ALL; _wapi.GetScrollInfo(hwnd,SB_VERT,FSI._getptr_); // 保存当前滑块位置,迟些进行比较 yPos := FSI.nPos; dd := 0; edelta := e.delta; ew := abs(round(edelta/120)); if edelta<0 and FSI.nMax>yPos then begin //dd++; dd += FWhileStep*ew; end if edelta>0 and FSI.nMin