1226 lines
35 KiB
Plaintext
1226 lines
35 KiB
Plaintext
unit utslvclgrid;
|
|
interface
|
|
uses utslvclauxiliary,utslvclmemstruct,utslvclgdi;
|
|
{**
|
|
@explan(说明) 表格控件相关 %%
|
|
@date(20220510)
|
|
**}
|
|
type TcustomGridCtl = class(TCustomControl) //自绘制表格基类
|
|
{**
|
|
@explan(说明) 自绘制表格控件 %%
|
|
**}
|
|
function Create(AOwner);override; //构造
|
|
begin
|
|
inherited;
|
|
FLocalX := 0;
|
|
FLocalY := 0;
|
|
Width := 300;
|
|
Height := 260;
|
|
FMouseSizeColumnWidth := 1;
|
|
FAutoScroll := 3;
|
|
FItemCount := 0;
|
|
FFixedRows := 1;
|
|
FColumFixed := 0;
|
|
FColWidth := 5; //10;
|
|
FRowWidth := 10;
|
|
FC_NORMAL := OCR_NORMAL;
|
|
FC_SIZE := OCR_SIZEWE;
|
|
FC_SIZE2 := OCR_SIZENS;
|
|
FMarginLeft := 1;
|
|
FMarginTop := 1;
|
|
FMarginRight := 0;
|
|
FMarginBottom := 0;
|
|
FRowHeight := 30;
|
|
FColsWidths := new tnumindexarray();
|
|
FRowsHeight := new tnumindexarray();
|
|
FVariableRows := false;
|
|
FSI := new TScrollinfo();
|
|
end
|
|
function GetItemRect(i);virtual; //根据行号获得其区域
|
|
begin
|
|
{**
|
|
@explan(说明) 获得行的区域 %%
|
|
@param(i)(integer) 行号 %%
|
|
@return(array) array(左,上,右,下);
|
|
**}
|
|
yrct := GetItemYBound(i);
|
|
if not yrct then return nil;
|
|
basex := FMarginLeft-FColWidth * GetXpos();
|
|
//r := array(basex,yrct[0],yrct[1],0);
|
|
r := array(basex,yrct[0],0,yrct[1]);
|
|
for ii := 0 to FColsWidths.length()-1 do
|
|
begin
|
|
basex += FColsWidths[ii];
|
|
end
|
|
r[2]:= basex;
|
|
return r;
|
|
end
|
|
function GetItemStartY(i);virtual; //获得行的top
|
|
begin
|
|
{**
|
|
@explan(说明) 获得行的区域范围 %%
|
|
@param(i)(integer) 行号 %%
|
|
@return(array) array(上,下);
|
|
**}
|
|
if(i<0 or i >= GetItemCount())then return nil;
|
|
yb := FMarginTop;
|
|
itv := FRowHeight;
|
|
if FVariableRows then
|
|
begin
|
|
for ii := 0 to i-1 do
|
|
begin
|
|
yb += FRowsHeight[ii];
|
|
end
|
|
itv := FRowWidth;
|
|
end else
|
|
yb += i * FRowHeight;
|
|
if i<FFixedRows then
|
|
begin
|
|
return yb;
|
|
end
|
|
yp := GetYPos();
|
|
yb -= yp * itv;
|
|
return yb;
|
|
end
|
|
function GetItemYBound(i);virtual; //获得行的
|
|
begin
|
|
{**
|
|
@explan(说明) 获得行的区域范围 %%
|
|
@param(i)(integer) 行号 %%
|
|
@return(array) array(上,下);
|
|
**}
|
|
r := GetItemStartY(i);
|
|
if ifnil(r)then return nil;
|
|
return array(r,r+GetRowHeight(i));
|
|
end
|
|
function GetSubItemRect(i,j);virtual;
|
|
begin
|
|
{**
|
|
@explan(说明) 获得cell的范围%%
|
|
@param(i)(integer) 行号 %%
|
|
@param(j)(integer) 列号 %%
|
|
@return(array) array(左,上,右,下);
|
|
**}
|
|
if not(j >= 0 and j<FColsWidths.length())then return nil;
|
|
yrct := GetItemYBound(i);
|
|
if not yrct then return nil;
|
|
r := array(0,yrct[0],0,yrct[1]);
|
|
basex := FMarginLeft-FColWidth * GetXpos();
|
|
x2 := FMarginLeft;
|
|
for ii := 0 to FColsWidths.length()-1 do
|
|
begin
|
|
if j=ii then
|
|
begin
|
|
if j<FColumFixed then
|
|
begin
|
|
r[0]:= x2;
|
|
r[2]:= x2+FColsWidths[ii];
|
|
end else
|
|
begin
|
|
r[0]:= basex;
|
|
r[2]:= basex+FColsWidths[ii];
|
|
end
|
|
return r;
|
|
end
|
|
vi := FColsWidths[ii];
|
|
basex += vi;
|
|
x2 += vi;
|
|
end
|
|
return r;
|
|
end
|
|
function GetTureSubItemRect(i,j);
|
|
begin
|
|
{**
|
|
@explan(说明) 获得真实的格子区域 ,在有合并表格中使用 %%
|
|
**}
|
|
for ii,v in FMergers do
|
|
begin
|
|
if v.CellInMerge(i,j)then
|
|
begin
|
|
return GetMergRect(v);
|
|
end
|
|
end
|
|
return GetSubItemRect(i,j);
|
|
end
|
|
function GetColIndexByPos(x);virtual;
|
|
begin
|
|
{**
|
|
@explan(说明) 通过坐标获得 列号 %%
|
|
@param(x)(integer) 坐标 %%
|
|
@return(integer) 行号
|
|
**}
|
|
r :=-1;
|
|
if x <= FMarginLeft then return r;
|
|
basex := FMarginLeft-FColWidth * GetXpos();
|
|
x2 := FMarginLeft;
|
|
for i := 0 to FColsWidths.length()-1 do
|
|
begin
|
|
vi := FColsWidths[i];
|
|
x2 += vi;
|
|
basex += vi;
|
|
if i<FColumFixed and x2 >= x then return i;
|
|
if basex >= x then return i;
|
|
end
|
|
return r;
|
|
end
|
|
function InvalidateItem(i);virtual;
|
|
begin
|
|
{**
|
|
@explan(说明) 刷新行%%
|
|
@param(i)(integer) 行号 %%
|
|
**}
|
|
bd := GetItemYBound(i);
|
|
if not bd then return false;
|
|
rec := ClientRect;
|
|
if bd[1]>rec[3]or bd[0]<rec[1]then return false;
|
|
rec[1]:= bd[0];
|
|
rec[3]:= bd[1];
|
|
InvalidateRect(rec,nil);
|
|
end
|
|
function InvalidateSubItem(i,j);virtual;
|
|
begin
|
|
{**
|
|
@explan(说明) 刷新cell的范围%%
|
|
@param(i)(integer) 行号 %%
|
|
@param(j)(integer) 列号 %%
|
|
**}
|
|
rec1 := GetSubItemRect(i,j);
|
|
if not rec1 then return false;
|
|
rec := ClientRect;
|
|
if rec1[1]>rec[3]or rec1[3]<rec[1]or rec1[0]>rec[2]or rec1[2]<rec[0]then return false;
|
|
InvalidateRect(rec1,false);
|
|
end
|
|
function GetRowIndexByPos(y);virtual;
|
|
begin
|
|
{**
|
|
@explan(说明) 通过坐标获得 行号 %%
|
|
@param(y)(integer) 坐标 %%
|
|
@return(integer) 行号
|
|
**}
|
|
r :=-1;
|
|
if y <= FMarginTop then return-1;
|
|
if FVariableRows then
|
|
begin
|
|
basex := FMarginTop-FRowWidth * GetYpos();
|
|
x2 := FMarginTop;
|
|
for i := 0 to FRowsHeight.length()-1 do
|
|
begin
|
|
vi := FRowsHeight[i];
|
|
x2 += vi;
|
|
basex += vi;
|
|
if x2 >= x then return i;
|
|
if basex >= x then return i;
|
|
end
|
|
end else
|
|
begin
|
|
r := integer((y-FMarginTop)/FRowHeight);
|
|
if y <= FYfiexed then
|
|
begin
|
|
if r >= FItemCount then return-1;
|
|
return r;
|
|
end
|
|
ybase := GetYPos();
|
|
r += ybase;
|
|
if r >= FItemCount then return-1;
|
|
return r;
|
|
end
|
|
return r;
|
|
end
|
|
function SetColumns(cls,beg,len);virtual;
|
|
begin
|
|
{**
|
|
@explan(说明) 设置列宽信息 %%
|
|
@param(cls)(array of integer) 列宽 %%
|
|
@param(beg)(integer) 开始位置 %%
|
|
@param(len)(integer) 替代长度 %%
|
|
**}
|
|
clsa := array();
|
|
for i,v in cls do
|
|
begin
|
|
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);
|
|
end
|
|
function SetRows(rows,beg,len);virtual;
|
|
begin
|
|
if not FVariableRows then return;
|
|
clsa := array();
|
|
for i,v in rows do
|
|
begin
|
|
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);
|
|
end
|
|
function GetColumnWidth(i);
|
|
begin
|
|
{**
|
|
@explan(说明) 获得第i列宽度 %%
|
|
@param(i)(integer) 列号 %%
|
|
@return(integer) 宽度 %%
|
|
**}
|
|
return FColsWidths[i];
|
|
end
|
|
function SetColumnWidth(i,w);
|
|
begin
|
|
{**
|
|
@explan(说明) 设置列宽 %%
|
|
@param(i)(integer) 列序号 %%
|
|
@param(w)(integer) 新宽度 0 %%
|
|
**}
|
|
vi := FColsWidths[i];
|
|
if vi >= 0 and w >= 0 and vi <> w then UpDateColumWidth(i,w);
|
|
end
|
|
function DrawCell(cvs,rec,i,j);virtual;
|
|
begin
|
|
{**
|
|
@explan(说明) 绘制单元格 %%
|
|
@param(cvs)(tcustomcanvas) 画布 %%
|
|
@param(rec)(array) array(左上右下) %%
|
|
@param(i)(integer) 行号 %%
|
|
@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
|
|
else
|
|
begin
|
|
cvs.brush.Color := color;
|
|
cvs.Draw("rectangle",dr,DFC_BUTTON,DFCS_BUTTONPUSH);
|
|
end
|
|
cvs.drawtext(format("%d,%d",i,j),rec,DT_VCENTER .| DT_SINGLELINE .| DT_CENTER .| DT_NOPREFIX);
|
|
end
|
|
function GetRowHeight(idx);
|
|
begin
|
|
{**
|
|
@explan(说明) 获得行高 %%
|
|
**}
|
|
if FVariableRows then return FRowsHeight[idx];
|
|
else return FRowHeight;
|
|
end
|
|
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();
|
|
// 计算需要重绘的区域
|
|
ps := PAINTSTRUCT().rcPaint;
|
|
if FMarginRight>0 then ps[2]:= min(ClientRect[2]-FMarginRight,ps[2]);
|
|
if FMarginBottom>0 then ps[3]:= min(ClientRect[3]-FMarginBottom,ps[3]);
|
|
FValidateRect := ps;
|
|
tp := ps[1];
|
|
bo := ps[3];
|
|
//***************计算表头区域*******************
|
|
basex := FMarginLeft-xpos * FColWidth;
|
|
x := basex;
|
|
x2 := FMarginLeft;
|
|
cvs.Font := font;
|
|
drawcol := array();
|
|
for i,v in FColsWidths.Data do
|
|
begin
|
|
if i<FColumFixed then
|
|
begin
|
|
if(x2+v >= ps[0])and x2<ps[2]then
|
|
begin
|
|
drawcol[i]:= array(x2,x2+v);
|
|
end
|
|
end
|
|
if i >= FColumFixed then
|
|
begin
|
|
if(x+v >= ps[0])and x<ps[2]then
|
|
begin
|
|
drawcol[i]:= array(x,x+v);
|
|
end
|
|
end
|
|
x2 += v;
|
|
x += v;
|
|
end
|
|
y2 := FMarginTop;
|
|
drawrow := array();
|
|
if FVariableRows then
|
|
begin
|
|
FRowsTemp := FRowsHeight.Data;
|
|
basey := FMarginTop-ypos * FRowWidth;
|
|
end else
|
|
begin
|
|
basey := FMarginTop-ypos * FRowHeight;
|
|
FRowsTemp := zeros(FItemCount)+FRowHeight;
|
|
end
|
|
y := basey;
|
|
for i,v in FRowsTemp do
|
|
begin
|
|
if i<FFixedRows then
|
|
begin
|
|
if(y2+v >= ps[1])and y2<ps[3]then
|
|
begin
|
|
drawrow[i]:= array(y2,y2+v);
|
|
end
|
|
end
|
|
if i >= FFixedRows then
|
|
begin
|
|
if(y+v >= ps[1])and y<ps[3]then
|
|
begin
|
|
drawrow[i]:= array(y,y+v);
|
|
end
|
|
end
|
|
y2 += v;
|
|
y += v;
|
|
end
|
|
parta := array();
|
|
partal := 0;
|
|
partb := array();
|
|
partbl := 0;
|
|
partc := array();
|
|
partcl := 0;
|
|
partd := array();
|
|
partdl := 0;
|
|
merga := array();
|
|
mergb := array();
|
|
mergc := array();
|
|
mergd := array();
|
|
for j,vj in drawcol do
|
|
begin
|
|
if vj[0]>= vj[1]then continue;
|
|
for i,vi in drawrow do
|
|
begin
|
|
if i<FFixedRows and j<FColumFixed then
|
|
begin
|
|
if FindMerge(i,j,merga)then
|
|
begin
|
|
end else
|
|
parta[partal++]:= array(array(vj[0],vi[0],vj[1],vi[1]),i,j);
|
|
end else
|
|
if i<FFixedRows and j >= FColumFixed then
|
|
begin
|
|
if FindMerge(i,j,mergb)then
|
|
begin
|
|
end else
|
|
partb[partbl++]:= array(array(vj[0],vi[0],vj[1],vi[1]),i,j);
|
|
end else
|
|
if i >= FFixedRows and j<FColumFixed then
|
|
begin
|
|
if FindMerge(i,j,mergc)then
|
|
begin
|
|
end else
|
|
partc[partcl++]:= array(array(vj[0],vi[0],vj[1],vi[1]),i,j);
|
|
end else
|
|
if i >= FFixedRows and j >= FColumFixed then
|
|
begin
|
|
if FindMerge(i,j,mergd)then
|
|
begin
|
|
end else
|
|
partd[partdl++]:= array(array(vj[0],vi[0],vj[1],vi[1]),i,j);
|
|
end
|
|
end
|
|
end
|
|
if parta or merga then
|
|
begin
|
|
DrawAllParts(cvs,parta,merga,array(FMarginLeft,FMarginTop,FXfiexed,FYfiexed));
|
|
end
|
|
if partb or mergb then
|
|
begin
|
|
DrawAllParts(cvs,partb,mergb,array(FXfiexed,FMarginTop,ps[2],FYfiexed));
|
|
end
|
|
if partc or mergc then
|
|
begin
|
|
DrawAllParts(cvs,partc,mergc,array(FMarginLeft,FYfiexed,FXfiexed,ps[3]));
|
|
end
|
|
if partd or mergd then
|
|
begin
|
|
DrawAllParts(cvs,partd,mergd,array(FXfiexed,FYfiexed,ps[2],ps[3]));
|
|
end
|
|
end
|
|
function MouseDown(o,e);override;
|
|
begin
|
|
if csDesigning in ComponentState then return false;
|
|
if e.button()<> mbLeft then return false;
|
|
if FC_CURRENT=FC_SIZE then //调整大小
|
|
begin
|
|
FSizeColum := 1;
|
|
_wapi.ClipCursor(FCursorRect);
|
|
return true;
|
|
end else
|
|
if FC_CURRENT=FC_SIZE2 then
|
|
begin
|
|
FSizeColum := 2;
|
|
_wapi.ClipCursor(FCursorRect);
|
|
return true;
|
|
end
|
|
end
|
|
function MouseUp(o,e);override;
|
|
begin
|
|
if FSizeColum then
|
|
begin
|
|
FSizeColum := false;
|
|
_wapi.ClipCursor(0);
|
|
return true;
|
|
end
|
|
end
|
|
function MouseMove(o,e);override;
|
|
begin
|
|
if csDesigning in ComponentState then return false;
|
|
if not FMouseSizeColumnWidth then
|
|
begin
|
|
setcursornormal();
|
|
return 0;
|
|
end
|
|
y := e.yPos;
|
|
X := e.xpos;
|
|
if FMouseSizeColumnWidth .& 1>0 then
|
|
begin
|
|
if x<FXfiexed then
|
|
begin
|
|
basex := FMarginLeft;
|
|
end else
|
|
begin
|
|
xdx := GetXpos();
|
|
basex := FMarginLeft-FColWidth * xdx;
|
|
end
|
|
end
|
|
if(FMouseSizeColumnWidth .& 2>0)and FVariableRows then
|
|
begin
|
|
basey := FMarginTop;
|
|
if y >= FYfiexed then
|
|
begin
|
|
xdx := GetYpos();
|
|
basey := FMarginTop-FRowWidth * xdx;
|
|
end
|
|
end
|
|
if(FMouseSizeColumnWidth=0)then
|
|
begin
|
|
setcursornormal();
|
|
return 0;
|
|
end
|
|
if FColsWidths.length()>0 and GetItemCount()>0 and x>(FMarginLeft+5)and y>(FMarginTop+5) {and y<(FMarginTop+FRowHeight*FFixedRows) }then
|
|
begin
|
|
if FSizeColum=1 then
|
|
begin
|
|
wd := FColsWidths[FCurrentSizeId];
|
|
UpDateColumWidth(FCurrentSizeId,wd+x-FCurrentSizePos);
|
|
FCurrentSizePos := x;
|
|
return true;
|
|
end else
|
|
if FSizeColum=2 then
|
|
begin
|
|
wd := FRowsHeight[FCurrentSizeId];
|
|
UpDateRowWidth(FCurrentSizeId,wd+y-FCurrentSizePos);
|
|
FCurrentSizePos := y;
|
|
return true;
|
|
end else
|
|
begin
|
|
bx := basex;
|
|
rc := ClientRect;
|
|
if FMouseSizeColumnWidth .& 1>0 then
|
|
begin
|
|
for i,v in FColsWidths.Data do
|
|
begin
|
|
if abs(x-bx-v)<3 then
|
|
begin
|
|
FCurrentSizeId := i;
|
|
FCurrentSizePos := x;
|
|
FCursorRect := array(clientToScreen(max(bx+6,rc[0]+6),y-10),clientToScreen(rc[2],y+10));
|
|
setcursorsize();
|
|
return true;
|
|
end
|
|
bx += v;
|
|
end
|
|
end
|
|
if FVariableRows and(FMouseSizeColumnWidth .& 2>0)then
|
|
begin
|
|
bx := basey;
|
|
for i,v in FRowsHeight.Data do
|
|
begin
|
|
if abs(y-bx-v)<3 then
|
|
begin
|
|
FCurrentSizeId := i;
|
|
FCurrentSizePos := y;
|
|
FCursorRect := array(clientToScreen(x-10,max(rc[1]+6,bx+6)),clientToScreen(x+10,rc[3]));
|
|
setcursorsize2();
|
|
return true;
|
|
end
|
|
bx += v;
|
|
end
|
|
end
|
|
end
|
|
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
|
|
function MergeCells(cells);
|
|
begin
|
|
{**
|
|
@explan(说明) 单元格 %%
|
|
@param(cells)(array) array(开始行,开始列,结束行,结束列) %%
|
|
**}
|
|
nm := new TMerger();
|
|
nm.SetMergeCells(cells);
|
|
if nm.isok then
|
|
begin
|
|
if not ifarray(FMergers)then FMergers := array();
|
|
FMergers[length(FMergers)]:= nm;
|
|
end
|
|
end
|
|
function GetMergeInfo();
|
|
begin
|
|
{**
|
|
@explan(说明) 获得合并信息 %%
|
|
**}
|
|
r := array();
|
|
for i,v in FMergers do
|
|
begin
|
|
r[i]:= v.FCells;
|
|
end
|
|
return r;
|
|
end
|
|
function CleanMergeCells();
|
|
begin
|
|
{**
|
|
@explan(说明) 清空合并信息 %%
|
|
**}
|
|
FMergers := array();
|
|
end
|
|
function GetGridMargin();
|
|
begin
|
|
return array(FMarginLeft,FMarginTop,FMarginRight,FMarginBottom);
|
|
end
|
|
function SetGridMargin(l,t,r,b);
|
|
begin
|
|
if l >= 0 then nl := integer(l);
|
|
if t >= 0 then nt := integer(t);
|
|
if r >= 0 then nr := integer(r);
|
|
if b >= 0 then nb := integer(b);
|
|
f := false;
|
|
if nl >= 0 and nl <> FMarginLeft then
|
|
begin
|
|
f := true;
|
|
FMarginLeft := nl;
|
|
end
|
|
if nt >= 0 and nt <> FMarginTop then
|
|
begin
|
|
f := true;
|
|
FMarginTop := nt;
|
|
end
|
|
if nr >= 0 and nr <> FMarginRight then
|
|
begin
|
|
//f := true;
|
|
FMarginRight := nr;
|
|
end
|
|
if nb >= 0 and nb <> FMarginBottom then
|
|
begin
|
|
//f := true;
|
|
FMarginBottom := nb;
|
|
end
|
|
if f then InitialScroll(nil,nil,0);
|
|
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;
|
|
property FixedRows read FFixedRows write SetFixedRows;
|
|
property FixedColumns read FColumFixed write SetFixedColumns;
|
|
property ColumnCount read GetColumnCount;
|
|
property VariableRows read FVariableRows write SetVariableRows;
|
|
{**
|
|
@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
|
|
for i,v in merga do
|
|
begin
|
|
rec := GetMergRect(v);
|
|
if not rec then return;
|
|
v.mergeid(ri,ci);
|
|
DrawCell(cvs,rec,ri,ci);
|
|
end
|
|
end
|
|
function GetMergRect(mr);
|
|
begin
|
|
rg := mr.GetRange();
|
|
rec := GetSubItemRect(rg[0],rg[1]);
|
|
rec2 := GetSubItemRect(rg[2],rg[3]);
|
|
if rec and rec2 then
|
|
begin
|
|
rec[2:3]:= rec2[2:3];
|
|
return rec;
|
|
end
|
|
return array();
|
|
end
|
|
function FindMerge(i,j,ret);
|
|
begin
|
|
for ii,v in FMergers do
|
|
begin
|
|
if v.CellInMerge(i,j)then
|
|
begin
|
|
f := true;
|
|
for k := 0 to length(ret)-1 do
|
|
begin
|
|
if ret[k]=v then
|
|
begin
|
|
f := false;
|
|
break;
|
|
end
|
|
end
|
|
if f then
|
|
begin
|
|
ret[length(ret)]:= v;
|
|
end
|
|
return v;
|
|
end
|
|
end
|
|
end
|
|
function GetItemCount();
|
|
begin
|
|
if FVariableRows then return FRowsHeight.Length();
|
|
return FItemCount;
|
|
end
|
|
function SetVariableRows(v);
|
|
begin
|
|
nv := v?true:false;
|
|
if nv <> FVariableRows then
|
|
begin
|
|
if not FVariableRows then
|
|
begin
|
|
if FItemCount>0 then
|
|
begin
|
|
FRowsHeight.splices(0,FRowsHeight.length(),(zeros(FItemCount)+FRowHeight));
|
|
end
|
|
end else
|
|
begin
|
|
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);
|
|
end
|
|
end
|
|
function GetColumnCount();
|
|
begin
|
|
return FColsWidths.length();
|
|
end
|
|
|
|
function SetItemCount(ct);
|
|
begin
|
|
if FItemCount <> ct and ct >= 0 then
|
|
begin
|
|
FItemCount := ct;
|
|
if not FVariableRows then InitialScroll(nil,nil,0);
|
|
end
|
|
end
|
|
function SetRowHeigt(h);
|
|
begin
|
|
if FRowHeight <> h and h >= 5 then
|
|
begin
|
|
FRowHeight := h;
|
|
InitialScroll(nil,nil,0);
|
|
end
|
|
end
|
|
function SetFixedColumns(rs);
|
|
begin
|
|
if rs >= 0 and FColumFixed <> rs then
|
|
begin
|
|
FColumFixed := rs;
|
|
InitialScroll(nil,nil,0);
|
|
end
|
|
end
|
|
function SetFixedRows(rs);
|
|
begin
|
|
if rs >= 0 and FFixedRows <> rs then
|
|
begin
|
|
FFixedRows := rs;
|
|
InitialScroll(nil,nil,0);
|
|
end
|
|
end
|
|
|
|
function UpDateColumWidth(idx,value);
|
|
begin
|
|
if idx >= 0 and value >= 0 then
|
|
begin
|
|
if FColsWidths[idx]=value then return;
|
|
FColsWidths[idx]:= value;
|
|
InitialScroll(nil,nil,0);
|
|
end
|
|
end
|
|
function UpDateRowWidth(idx,value);
|
|
begin
|
|
if FVariableRows and idx >= 0 and value>0 then
|
|
begin
|
|
if FRowsHeight[idx]=value then return;
|
|
FRowsHeight[idx]:= value;
|
|
InitialScroll(nil,nil,0);
|
|
end
|
|
end
|
|
|
|
function UpDateFixed(); //更新固定宽度
|
|
begin
|
|
xfix := 0;
|
|
FxWidth := 0;
|
|
nx := min(FColumFixed,FColsWidths.length())-1;
|
|
for i := 0 to FColsWidths.length()-1 do
|
|
begin
|
|
vi := FColsWidths[i];
|
|
if i <= nx then xfix += vi;
|
|
FxWidth += vi;
|
|
end
|
|
if FVariableRows then
|
|
begin
|
|
FyHeight := FMarginTop;
|
|
FYfiexed := FMarginTop;
|
|
ny := min(FFixedRows,FRowsHeight.length())-1;
|
|
for i := 0 to FRowsHeight.length()-1 do
|
|
begin
|
|
vi := FRowsHeight[i];
|
|
if i <= ny then FYfiexed += vi;
|
|
FyHeight += vi;
|
|
end
|
|
end else
|
|
begin
|
|
FYfiexed := FMarginTop+FFixedRows * FRowHeight;
|
|
end
|
|
FXfiexed := FMarginLeft+xfix;
|
|
end
|
|
function setcursorsize2();
|
|
begin
|
|
IF FC_CURRENT <> FC_SIZE2 then
|
|
begin
|
|
cursor := FC_SIZE2;
|
|
FC_CURRENT := FC_SIZE2;
|
|
end
|
|
end
|
|
function setcursorsize();
|
|
begin
|
|
IF FC_CURRENT <> FC_SIZE then
|
|
begin
|
|
cursor := FC_SIZE;
|
|
FC_CURRENT := FC_SIZE;
|
|
end
|
|
end
|
|
function setcursornormal();
|
|
begin
|
|
if FC_CURRENT <> FC_NORMAL then
|
|
begin
|
|
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
|
|
FMergers;
|
|
FAutoScroll;
|
|
//固定***********
|
|
FXfiexed;
|
|
FYfiexed;
|
|
//********鼠标*************
|
|
FC_NORMAL;
|
|
FC_SIZE;
|
|
FC_SIZE2;
|
|
FC_CURRENT;
|
|
//******位置***************
|
|
FMarginLeft;
|
|
FMarginTop;
|
|
FMarginRight;
|
|
FMarginBottom;
|
|
//*******表头***********
|
|
FColWidth;
|
|
FRowWidth; // 变高基础高度
|
|
FxWidth;
|
|
FyHeight;
|
|
FFixedRows;
|
|
FColsWidths;
|
|
FRowsHeight;
|
|
FColumFixed;
|
|
FRowHeight;
|
|
FVariableRows; //列高可变
|
|
//****************表体*******************
|
|
FItemCount;
|
|
//*******滚动条*******
|
|
FSI;
|
|
//调整列宽
|
|
FMouseSizeColumnWidth;
|
|
FSizeColum;
|
|
FCursorRect;
|
|
FCurrentSizeId;
|
|
FCurrentSizePos;
|
|
end
|
|
implementation
|
|
type TCanvsRgnClipAutoSave=class()//canvas 裁剪
|
|
{**
|
|
@expan(说明) 裁剪canvas区域,销毁时还原 %%
|
|
**}
|
|
function Create(cvs,rec);
|
|
begin
|
|
{**
|
|
@explan(说明)构造裁剪对象 %%
|
|
@param(cvs)(tcustomcanvas) canvas 对象 %%
|
|
@param(rec)(array(左上右下))区域 %%
|
|
**}
|
|
if(cvs is class(tcustomcanvas))and cvs.HandleAllocated()and ifarray(rec)then
|
|
begin
|
|
FW32api := cvs._wapi;
|
|
FCvsHandle := cvs.Handle;
|
|
FCrg := FW32api.CreateRectRgn(rec[0],rec[1],rec[2],rec[3]);
|
|
FBKrg := FW32api.SelectClipRgn(FCvsHandle,FCrg); //裁剪区域
|
|
end
|
|
end
|
|
function Destroy();
|
|
begin
|
|
if FW32api and FCvsHandle and FBKrg and FCrg then
|
|
begin
|
|
FW32api.SelectClipRgn(FCvsHandle,FBKrg); //恢复区域
|
|
FW32api.DeleteObject(FCrg); //销毁区域
|
|
end
|
|
FW32api := nil;
|
|
end
|
|
private
|
|
FBKrg;
|
|
FCrg;
|
|
FCvsHandle;
|
|
FW32api;
|
|
end
|
|
|
|
end. |