Update utslvclgrid.tsf

统一滚动条实现
This commit is contained in:
JianjunLiu 2022-10-21 17:30:02 +08:00
parent 7c79268504
commit 1d410164f6
1 changed files with 174 additions and 363 deletions

View File

@ -5,10 +5,101 @@ uses utslvclauxiliary,utslvclmemstruct,utslvclgdi;
@explan(说明) 表格控件相关 %%
@date(20220510)
**}
type TcustomGridCtl = class(TCustomControl) //自绘制表格基类
type TcustomGridCtl = class(tcustomscrollcontrol) //自绘制表格基类
{**
@explan(说明) 自绘制表格控件 %%
**}
protected
function GetClientXCapacity();virtual; //宽度容量
begin
r := integer(ClientRect[2]/GetXScrollDelta());
return r;
end
function GetClientYCapacity();virtual; //高度容量
begin
r := integer(ClientRect[3]/GetYScrollDelta());
return r;
end
function GetClientXCount();virtual; //宽度间隔
begin
r := integer(0.99+ allwidth()/FColWidth);
return r;
end
function GetClientYCount();virtual; //高度项
begin
return integer(0.99+allheigth()/FRowHeight);
end
function GetXScrollDelta();override;
begin
return FColWidth;
end
function GetYScrollDelta();override;
begin
return FRowHeight;
end
function PositionChanged();virtual;
begin
InvalidateRect(nil,false);
end
function UpDateScrollBar();
begin
DoControlAlign();
end
public
function IncPaintLock();
begin
BeginUpdate();
end
function DecPaintLock();
begin
EndUpdate();
end
function DoEndUpDate();override;
begin
if not(IsUpDating())then
begin
if FScroolChanged then
begin
FScroolChanged := false;
UpDateScrollBar();
end
end
inherited;
end
function DoControlAlign();override;
begin
UpDateFixed();
InitialScroll();
end
private
function allwidth();
begin
//return (FxWidth-FXfiexed);
r := 0;
for i:= 0 to FColsWidths.length()-1 do
begin
r+=FColsWidths[i];
end
return r;
end
function allheigth();
begin
//return FyHeight-FYfiexed;
if FVariableRows then
begin
r := 0;
for i:= 0 to FRowsHeight.length()-1 do
begin
r+=FRowsHeight[i];
end
return r;
end else
begin
r := FRowHeight*FItemCount;
return r;
end
end
public
function Create(AOwner);override; //构造
begin
inherited;
@ -16,12 +107,10 @@ type TcustomGridCtl = class(TCustomControl) //
function AfterConstruction();override;
begin
inherited;
FLocalX := 0;
FLocalY := 0;
Width := 300;
Height := 260;
FMouseSizeColumnWidth := 1;
FAutoScroll := 3;
AutoScroll := 3;
FItemCount := 0;
FFixedRows := 1;
FColumFixed := 0;
@ -38,7 +127,6 @@ type TcustomGridCtl = class(TCustomControl) //
FColsWidths := new tnumindexarray();
FRowsHeight := new tnumindexarray();
FVariableRows := false;
FSI := new TScrollinfo();
end
function GetItemRect(i);virtual; //根据行号获得其区域
begin
@ -75,9 +163,9 @@ type TcustomGridCtl = class(TCustomControl) //
begin
yb += FRowsHeight[ii];
end
itv := FRowWidth;
//itv := FRowWidth;
end else
yb += i * FRowHeight;
yb += i * FRowHeight;
if i<FFixedRows then
begin
return yb;
@ -244,7 +332,7 @@ type TcustomGridCtl = class(TCustomControl) //
if v >= 0 then clsa[length(clsa)]:= v;
end
FColsWidths.splices(beg>0?beg:0,len >= 0?len:FColsWidths.Length(),clsa);
InitialScroll(nil,nil,0);
DoControlAlign();
end
function SetRows(rows,beg,len);virtual;
begin
@ -255,7 +343,7 @@ type TcustomGridCtl = class(TCustomControl) //
if v>0 then clsa[length(clsa)]:= v;
end
FRowsHeight.splices(beg>0?beg:0,len >= 0?len:FRowsHeight.Length(),clsa);
InitialScroll(nil,nil,0);
DoControlAlign();
end
function GetColumnWidth(i);
begin
@ -286,7 +374,10 @@ type TcustomGridCtl = class(TCustomControl) //
@param(j)(integer) 列号 %%
**}
dr := array(rec[0:1],rec[2:3]);
if i<FFixedRows or j<FColumFixed then cvs.Draw("FrameControl",dr,DFC_BUTTON,DFCS_BUTTONPUSH); //DFCS_CHECKED DFCS_FLAT
if i<FFixedRows or j<FColumFixed then
begin
cvs.Draw("FrameControl",dr,DFC_BUTTON,DFCS_BUTTONPUSH); //DFCS_CHECKED DFCS_FLAT
end
else
begin
cvs.brush.Color := color;
@ -305,14 +396,6 @@ type TcustomGridCtl = class(TCustomControl) //
function Paint();override;
begin
cvs := Canvas;
//*****************获得基准点*************************************
{FSI.fMask := SIF_POS;
hwnd := self.Handle;
_wapi.GetScrollInfo(hwnd, SB_VERT, FSI._getptr_);
yPos := FSI.nPos;
// 获得水平滚动条的位置
_wapi.GetScrollInfo(hwnd, SB_HORZ, FSI._getptr_);
xPos := FSI.nPos;}
xPos := GetXpos();
ypos := GetYpos();
// 计算需要重绘的区域
@ -352,7 +435,7 @@ type TcustomGridCtl = class(TCustomControl) //
if FVariableRows then
begin
FRowsTemp := FRowsHeight.Data;
basey := FMarginTop-ypos * FRowWidth;
basey := FMarginTop-ypos * FRowHeight;//FRowWidth;
end else
begin
basey := FMarginTop-ypos * FRowHeight;
@ -495,7 +578,7 @@ type TcustomGridCtl = class(TCustomControl) //
if y >= FYfiexed then
begin
xdx := GetYpos();
basey := FMarginTop-FRowWidth * xdx;
basey := FMarginTop-FRowHeight * xdx;
end
end
if(FMouseSizeColumnWidth=0)then
@ -557,166 +640,7 @@ type TcustomGridCtl = class(TCustomControl) //
end
setcursornormal();
return false;
end
//系统处理函数
function DoWMSIZE(o,e);override; //大小调整
begin
InitialScroll(e.lolParam,e.hilparam);
inherited;
end
function DoMouseWheel(o,e);override;
begin
hwnd := self.Handle;
FSI.fMask := SIF_ALL;
_wapi.GetScrollInfo(hwnd,SB_VERT,FSI._getptr_);
// 保存当前滑块位置,迟些进行比较
yPos := FSI.nPos;
dd := 0;
if e.delta<0 and FSI.nMax>yPos then
begin
dd++;
end
if e.delta>0 and FSI.nMin<yPos then
begin
dd--;
end
if not dd then return;
FSI.fMask := SIF_POS;
FSI.nPos := yPos+dd;
_wapi.SetScrollInfo(hwnd,SB_VERT,FSI._getptr_,TRUE);
// 获得滚动条滑块的位置,由于窗口调整,它可能不是同一个值
_wapi.GetScrollInfo(hwnd,SB_VERT,FSI._getptr_);
FLocalY := FSI.nPos;
dd := yPos-FSI.nPos;
if dd then
begin
//_wapi.ScrollWindow(hwnd, 0, FRowHeight * (dd), nil, ClipScroll());
ivrect := ClientRect;
ivrect[1]:= FYfiexed; //FMarginTop+FRowHeight*FFixedRows;
InvalidateRect(ivrect,false);
end
end
function DoVScroll(o,e);override;
begin
// 获得垂直滚动条的所有信息
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
FSI.nPos -= FSI.nPage;
end
// 用户点击滑块下边的滚动条轴
SB_PAGEDOWN:
begin
FSI.nPos += FSI.nPage;
end
// 用户拖动滚动条
SB_THUMBTRACK:
begin
FSI.nPos := FSI.nTrackPos;
end
end
// 设置滚动条滑块的新位置
if FSI.nPos=yPos then return;
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
//_wapi.ScrollWindow(hwnd, 0, FRowHeight * (yPos - FSI.nPos), nil, ClipScroll());
ivrect := ClientRect;
ivrect[1]:= FYfiexed; //FMarginTop+FRowHeight*FFixedRows;
InvalidateRect(ivrect,false);
//UpdateWindow(hwnd);
end
return 0;
end
function DoHScroll(o,e);override;
begin
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
FSI.nPos := FSI.nTrackPos;
end
end;
if FSI.nPos=xPos then return;
// 设置滚动条滑块的新位置
FSI.fMask := SIF_POS;
_wapi.SetScrollInfo(e.hwnd,SB_HORZ,FSI._getptr_,TRUE);
// 获得滚动条滑块的位置,由于窗口调整,它可能不是同一个值
_wapi.GetScrollInfo(e.hwnd,SB_HORZ,FSI._getptr_);
// 与此前的保存的值进行比较,如果不同则滚动窗口
FLocalX := FSI.nPos;
if(FSI.nPos <> xPos)then
begin
//_wapi.ScrollWindow(e.hwnd, FColWidth * (xPos - FSI.nPos), 0, NIL,ClipScroll());
ivrect := ClientRect;
ivrect[0]:= FXfiexed; //FMarginTop+FRowHeight*FFixedRows;
InvalidateRect(ivrect,false);
//UpdateWindow(hwnd);
end
end
end
function MergeCells(cells);
begin
{**
@ -781,10 +705,9 @@ type TcustomGridCtl = class(TCustomControl) //
//f := true;
FMarginBottom := nb;
end
if f then InitialScroll(nil,nil,0);
if f then DoControlAlign();
end
//*******************
property AutoScroll read FAutoScroll write setAutoScroll;
property ItemCount read GetItemCount write SetItemCount;
property ItemHeight read FRowHeight write SetRowHeigt;
property MouseSizeCell read FMouseSizeColumnWidth write FMouseSizeColumnWidth;
@ -796,114 +719,14 @@ type TcustomGridCtl = class(TCustomControl) //
@param(ItemCount)(integer) 行数 %%
@param(MouseSizeCell)(bool) 鼠标改变列宽 %%
@param(FixedRows)(integer) 固定的行数作为列标 %%
**}
protected
function ItemUpDated(flag,idx);virtual;
begin
{**
@explan(说明) 更新状态 %%
@param(flag)(bool) 是否强制刷新,默认当项宽度不变的时候不刷新 %%
@param(idx)(integer) 更新id以后的序号 %%
**}
if HandleAllocated()and not(IsUpDating())then
begin
InitialScroll(nil,nil,idx);
end
end
function InitialScroll(x,y,idx);virtual;
begin
if not HandleAllocated()then return;
UpDateFixed();
if IsUpDating()then return;
if not(x>0 and y>0)then
begin
rc := ClientRect;
xClient := rc[2];
yClient := rc[3];
end else
begin
xClient := x;
yClient := y;
end
xClient -= FXfiexed;
yClient -= FYfiexed;
if xClient<FRowHeight or yClient<10 then return;
pt := New TPAINTCOUNT(self);
hwnd := Handle;
ItemUpDated();
// 设置垂直滚动条范围和页面大小(设置页面大小将决定滑块的粗细)
FSI.fMask := SIF_RANGE .| SIF_PAGE;
FSI.nMin := 0;
if FVariableRows then
begin
FSI.nMax :=(FAutoScroll .& 1)?((FyHeight-FYfiexed)/FRowWidth+1):0;
FSI.nPage := integer((yClient)/FRowWidth);
end else
begin
FSI.nMax :=(FAutoScroll .& 1)?(ItemCount-FixedRows):0;
FSI.nPage := integer((yClient)/FRowHeight);
//FSI.nMax := (FAutoScroll .& 1)?( ItemCount-FixedRows):0;
//FSI.nPage := integer((yClient) / FRowHeight);
end
_wapi.SetScrollInfo(hwnd,SB_VERT,FSI._getptr_,true);
FSI.fMask := SIF_POS;
_wapi.GetScrollInfo(hwnd,SB_VERT,FSI._getptr_);
FLocalY := FSI.nPos;
// 设置水平滚动条范围和页面大小(设置页面大小将决定滑块的粗细)
FSI.cbSize := FSI._size_;
FSI.fMask := SIF_RANGE .| SIF_PAGE;
FSI.nMin := 0;
FSI.nMax :=(FAutoScroll .& 2)?integer((FxWidth-FXfiexed)/FColWidth+1):0;
FSI.nPage := integer((xClient)/FColWidth); //+1
_wapi.SetScrollInfo(hwnd,SB_HORZ,FSI._getptr_,TRUE);
FSI.fMask := SIF_POS;
_wapi.GetScrollInfo(hwnd,SB_HORZ,FSI._getptr_);
FLocalX := FSI.nPos;
if idx <= 0 then InvalidateRect(nil,false);
end
function GetXpos();virtual; //x位置
begin
return FLocalX;
if HandleAllocated()then
begin
FSI.fMask := SIF_ALL;
_wapi.GetScrollInfo(self.Handle,SB_HORZ,FSI._getptr_);
// 保存当前滑块位置,迟些进行比较
return FSI.nPos;
end
return 0;
end
function GetYPos();virtual; //y位置
begin
return FLocalY;
if HandleAllocated()then
begin
FSI.fMask := SIF_ALL;
hwnd := Handle;
_wapi.GetScrollInfo(hwnd,SB_VERT,FSI._getptr_);
// 保存当前滑块位置,迟些进行比较
return FSI.nPos;
end
return 0;
end
**}
private
FLocalX;
FLocalY;
function DrawAllParts(cvs,part,merg,rec);
begin
bcvs := new TCanvsRgnClipAutoSave(cvs,rec);
for i,v in part do DrawCell(cvs,v[0],v[1],v[2]);
drawmerge(cvs,merg);
return;
try
rgC := _wapi.CreateRectRgn(rec[0],rec[1],rec[2],rec[3]);
bkrg := _wapi.SelectClipRgn(cvs.Handle,rgc); //裁剪区域
for i,v in part do DrawCell(cvs,v[0],v[1],v[2]);
drawmerge(cvs,merg);
except
_wapi.SelectClipRgn(cvs.Handle,bkrg); //恢复区域
_wapi.DeleteObject(rgC); //销毁区域
end;
end
function drawmerge(cvs,merga);
begin
@ -971,18 +794,10 @@ type TcustomGridCtl = class(TCustomControl) //
FItemCount := FRowsHeight.Length();
end
FVariableRows := nv;
InitialScroll(nil,nil,0);
end
end
function setAutoScroll(sc);
begin
if not(nv in array(0,1,2,3))then return 0;
if FAutoScroll <> sc then
begin
FAutoScroll := sc;
InitialScroll(nil,nil,0);
DoControlAlign();
end
end
function GetColumnCount();
begin
return FColsWidths.length();
@ -993,7 +808,7 @@ type TcustomGridCtl = class(TCustomControl) //
if FItemCount <> ct and ct >= 0 then
begin
FItemCount := ct;
if not FVariableRows then InitialScroll(nil,nil,0);
if not FVariableRows then DoControlAlign();
end
end
function SetRowHeigt(h);
@ -1001,7 +816,7 @@ type TcustomGridCtl = class(TCustomControl) //
if FRowHeight <> h and h >= 5 then
begin
FRowHeight := h;
InitialScroll(nil,nil,0);
DoControlAlign();
end
end
function SetFixedColumns(rs);
@ -1009,7 +824,7 @@ type TcustomGridCtl = class(TCustomControl) //
if rs >= 0 and FColumFixed <> rs then
begin
FColumFixed := rs;
InitialScroll(nil,nil,0);
DoControlAlign();
end
end
function SetFixedRows(rs);
@ -1017,7 +832,7 @@ type TcustomGridCtl = class(TCustomControl) //
if rs >= 0 and FFixedRows <> rs then
begin
FFixedRows := rs;
InitialScroll(nil,nil,0);
DoControlAlign();
end
end
@ -1027,7 +842,7 @@ type TcustomGridCtl = class(TCustomControl) //
begin
if FColsWidths[idx]=value then return;
FColsWidths[idx]:= value;
InitialScroll(nil,nil,0);
DoControlAlign();
end
end
function UpDateRowWidth(idx,value);
@ -1036,7 +851,7 @@ type TcustomGridCtl = class(TCustomControl) //
begin
if FRowsHeight[idx]=value then return;
FRowsHeight[idx]:= value;
InitialScroll(nil,nil,0);
DoControlAlign();
end
end
@ -1091,69 +906,7 @@ type TcustomGridCtl = class(TCustomControl) //
cursor := FC_NORMAL;
FC_CURRENT := FC_NORMAL;
end
end
function GetHeaderRect();
begin
end
type TPAINTCOUNT=class
{**
@explan(说明) 绘制计数 %%
**}
function create(v);
begin
if v is class(TControl)then
begin
FPainter := v;
v.BeginUpDate();
end
end
function Destroy();
begin
if FPainter then FPainter.EndUpDate();
FPainter := nil;
end
FPainter;
end
type TMerger=class
public
FCells;
function Create();
begin
FCells := array(); // r,c value
end
function isok();
begin
return length(FCells);
end
function mergeid(i,j);
begin
i := FCells[0];
j := FCells[1];
end
function CellInMerge(i,j);
begin
if isok()then
begin
if i >= FCells[0]and i <= FCells[2]and j >= FCells[1]and j <= FCells[3]then return true;
end
return false;
end
function GetRange();
begin
r := array();
if isok()then
begin
return FCells;
end
return r;
end
function SetMergeCells(rec);
begin
FCells := array();
if not ifarray(rec)then return;
if(rec[2]>= rec[0]and rec[3]>rec[1])or(rec[2]>rec[0]and rec[3]>= rec[1])then FCells := rec;
end
end
end
FMergers;
FAutoScroll;
//固定***********
@ -1183,7 +936,6 @@ type TcustomGridCtl = class(TCustomControl) //
//****************表体*******************
FItemCount;
//*******滚动条*******
FSI;
//调整列宽
FMouseSizeColumnWidth;
FSizeColum;
@ -1192,6 +944,65 @@ type TcustomGridCtl = class(TCustomControl) //
FCurrentSizePos;
end
implementation
type TPAINTCOUNT=class
{**
@explan(说明) 绘制计数 %%
**}
function create(v);
begin
if v is class(TControl)then
begin
FPainter := v;
v.BeginUpDate();
end
end
function Destroy();
begin
if FPainter then FPainter.EndUpDate();
FPainter := nil;
end
FPainter;
end
type TMerger=class
public
FCells;
function Create();
begin
FCells := array(); // r,c value
end
function isok();
begin
return length(FCells);
end
function mergeid(i,j);
begin
i := FCells[0];
j := FCells[1];
end
function CellInMerge(i,j);
begin
if isok()then
begin
if i >= FCells[0]and i <= FCells[2]and j >= FCells[1]and j <= FCells[3]then return true;
end
return false;
end
function GetRange();
begin
r := array();
if isok()then
begin
return FCells;
end
return r;
end
function SetMergeCells(rec);
begin
FCells := array();
if not ifarray(rec)then return;
if(rec[2]>= rec[0]and rec[3]>rec[1])or(rec[2]>rec[0]and rec[3]>= rec[1])then FCells := rec;
end
end
type TCanvsRgnClipAutoSave=class()//canvas 裁剪
{**
@expan(说明) 裁剪canvas区域,销毁时还原 %%