TPanel
|
TAcReportCtrl------相当于一个Grid
procedure TAcReportCtrl.DrawReport(hPaintDc: HDC; ps: TPaintStruct; rectPaint: TRect);
// 绘制所有与失效区相交的矩形
for I := 0 to FLineList.Count - 1 do
begin
ThisLine := TAcReportLine(FLineList[I]);
for J := 0 to TAcReportLine(FLineList[i]).FCells.Count - 1 do
begin
ThisCell := TAcReportCell(ThisLine.FCells[J]);
if ThisCell.OwnerCell = nil then
begin
ThisCell.DrawCellFrame(ACanvas, FPreviewStatus);
ThisCell.Draw(ACanvas);
if not FPreviewStatus and (ThisCell.Script.Count > 0) then
ThisCell.DrawScriptFlag(ACanvas);
end;
end;
end;
if (Report.PageType <> ptDialog) and (DocMode = dmPrinting) then
for I := 0 to Report.Objects.Count - 1 do
begin
t := Report.Objects[I];
t.DrawCellFrame(ACanvas, FPreviewStatus);
t.Draw(ACanvas);
if not FPreviewStatus and (t.Script.Count > 0) then
t.DrawScriptFlag(ACanvas);
end;
procedure TEAReportDrawGrid.PaintGrid;
var
I, N: Integer;
vRow: TEAReportDrawGridRow;
begin
if CanPaint then
begin
for I := 0 to Count - 1 do
begin
vRow := Rows[I];
for N := 0 to vRow.Count - 1 do
vRow.Cells[N].Paint;
end;
if CanDrawDragFrame then
PaintDragFrame;
end;
end;
procedure TEAReportStaticGrid.PaintDataGrid(AWidthArr: array of Integer);
var
I, N, vInt1, vInt2, vDataHeight, vDataCount, vRealTitleHeight, vOff: Integer;
vR1, vR2, vR3: TRect;
vDrawStr: string;
vFlags: Longint;
vRectArr: TEARectArr;
begin
if FOwner = nil then
Exit;
vR1 := FOwner.RealDisplayRect;
if FShowTitle then
vRealTitleHeight := GetViewScaleSize(FTitleHeight, ReportPmm.ViewScale)
else
vRealTitleHeight := 0;
vDataCount := Trunc((TEARectFun.GetRectHeight(vR1)
- vRealTitleHeight) / GetViewScaleSize(FDataHeight, ReportPmm.ViewScale));
if vDataCount > RecordCount then
vDataCount := RecordCount;
vOff := 0;
if FDataFillMode = edfmAutoHeight then
begin
if vDataCount <> 0 then
begin
vDataHeight := Trunc((TEARectFun.GetRectHeight(vR1) - vRealTitleHeight) / vDataCount);
vOff := TEARectFun.GetRectHeight(vR1) - vRealTitleHeight - vDataHeight * vDataCount;
if vOff < 0 then
vOff := 0;
end
else
vDataHeight := GetViewScaleSize(FDataHeight, ReportPmm.ViewScale);
end
else if FDataFillMode = edfmFixHeight then
begin
vDataHeight := GetViewScaleSize(FDataHeight, ReportPmm.ViewScale);
end
else begin //FDataFillMode = ecwsDynamic
vDataHeight := GetViewScaleSize(FDataHeight, ReportPmm.ViewScale);
if (vDataCount < Self.RecordCount) and CanDynamicAdjustSize then
begin
vR1 := FOwner.RealDisplayRect;
vDataCount := RecordCount;
vRectArr := AdjustDynamicSize;
if Length(vRectArr) > 0 then
begin
TEAPaintFun.InvalidateRectArr(ReportPmm.Handle, vRectArr);
end;
end;
end;
if (vDataCount = 0) or (TitleCount = 0) then
Exit;
vInt2 := vR1.Left;
Canvas.Brush.Color := FOwner.Color;
for I := 0 to TitleCount - 1 do
begin
Canvas.Font.Assign(Titles[I].FValueInfo.FFont);
Canvas.Font.Size := GetViewScaleSize(Canvas.Font.Size, ReportPmm.ViewScale);
vR2.Left := vInt2 + 1;
vR2.Right := vInt2 + AWidthArr[I] - 1;
vInt2 := vInt2 + AWidthArr[I];
if vR2.Right > vR1.Right then
vR2.Right := vR1.Right;
vFlags := DT_EXPANDTABS or cSWordWraps[Titles[I].FValueInfo.FWordWrap]
or cSHorzPosArr[Titles[I].FValueInfo.FHorzPos];
vInt1 := vR1.Top + vRealTitleHeight;
for N := 0 to vDataCount - 1 do
begin
vR2.Top := vInt1;
vR2.Bottom := vInt1 + vDataHeight;
if (FDataFillMode = edfmAutoHeight) then
begin
if N < vOff then
Inc(vR2.Bottom);
if (N = vDataCount - 1) and (vR2.Bottom < vR1.Bottom) then
begin
vR2.Bottom := vR1.Bottom;
end;
end;
vInt1 := vR2.Bottom;
vDrawStr := Cells[N, I];
vR3 := vR2;
Inc(vR3.Left, 2);
vR3 := TEAPaintFun.GetTextRect(Canvas, vR3, vDrawStr,
Titles[I].FValueInfo.FVertPos, Titles[I].FValueInfo.FWordWrap);
DrawText(Canvas.Handle, PChar(vDrawStr), -1, vR3, vFlags);
if (vR1.Right - vR2.Right > 1) then
TEAPaintFun.Draw_Line(Canvas, vInt2, vR2.Top, vInt2, vInt1);
if (I = 0) and (vR1.Bottom - vInt1 > 1) then
TEAPaintFun.Draw_Line(Canvas, vR1.Left + 1, vInt1, vR1.Right, vInt1);
if (vInt1 >= vR1.Bottom) or (vInt2 > vR1.Right) then
Break;
end;
end;
end;
EReport中
component是其核心源码
WMPaint
WMLButtonDBLClk
WMLButtonDown
TReportCell属于TReportLine,TReportCell
TReportLine属于 TReportControl,TReportLine的所有水平坐标应该相接,
纵坐标不一定在一条线上
TReportControl = Class(TWinControl) 纸张大小相关 可交互操作
TReportRunTime = Class(TComponent)与数据集相关
一个Line中的所有Cell是同样高度前后相接排成一行
一个Cell若包含子Cell,则这些子Cell必同样宽度上下相接排成一列(其实就是多行)。
合并后的原左上角的cell包含了下面的Cell.
Table一个表格
NewTable(ColNumber, RowNumber: Integer);
创建Table时指定行列,则有一个最基本行。
CombineCell;
先进行行合并。同一行的Cell除第一个以外全部从所属的行中去掉。
第一个Cell的宽度修改为所有选中Cell的宽度之和。
列合并,左上角的Cell owned所有其他选中的cell.其它选中的cell
CombineCellHorz;
EhReport1.VSplitCell(VSplitForm.VSplitCount.AsInteger);
SplitCell:核心
RemoveOwnedCell
VSplitCell(Number: Integer);
纵列水平Split,最多Split为Number个
调整第一列的宽度
以要Split的Cell为模板,创建一个Cell,插入到该Cell所属行。
以要Split的Cell Owned的Cell为模板,创建一列Cell。
一个Cell可以包含一个表格,选择单元格时,可以仅包含Cell中的Table中的表格。
如果跨越两个表格,则其中一个表格必须完全被包含。
EasyGrid加入嵌套则可实现任意网格。
先仅考虑固定行列的网格,及其分割合并。
复杂的表格可以看作简单网格的嵌套。
一个网格由Cell(行*列)组成,合并,拆分都是这些cell的拆分。
一个网格由Cell组成。Cell包含0个或多个网格。
TCustomEasyGrid.SetMerges
EasyGrid中每一个被合并的Cell,都记录有被合并后的最大区域。
AMergeRect中的数值为Cell的逻辑坐标。
for i := AMergeRect.Left to AMergeRect.Right do
for j := AMergeRect.Top to AMergeRect.Bottom do
begin
Cells[i,j].Merge := AMergeRect;
CellToCell(@ValueCellInfo, Cells[i, j]);
if (i <> AMergeRect.Left) or (j <> AMergeRect.Top) then
begin
Cells[i,j].ForeText := '';
Cells[i,j].BackText := '';
end;
end;
EsayGrid行模式。每一行的最小的CELL数目是一样的。
EReport行模式。如果不用嵌套,EReport可以把两个基本单元合并为1个,再拆分为3个。而EsayGrid不行。只能再拆分为2个。
/////////////////////////////////
EhLib
Gridseh
DrawCells//行模式
CurRow := ARow;
Where.Top := StartY;
while (Where.Top < StopY) and (CurRow < RowCount) do
begin
CurCol := ACol;
Where.Left := StartX;
Where.Bottom := Where.Top + RowHeights[CurRow];
while (Where.Left < StopX) and (CurCol < ColCount) do
//EasyGrid
DrawCells
// 双层行列循环(先行后列)
while (Where.Top < DrawRect.Bottom) and (CurRow <= EndRow) do
begin
CurCol := StartCol;
Where.Left := DrawRect.Left;
while (Where.Left < DrawRect.Right) and (CurCol <= EndCol) do
EasyGrid实现斜线 ,各种控件的插入。
数据获取,类似TStringgrid由外部在事件中提供,或者直接确定其文本。
二维转换为1维。设计时和运行时,运行时网格固定不可在增添。
一个List按行的顺序管理所有Cell的指针。
清单式网格打印时,网格固定,
清单式网格输入数据时行数目不确定。分为多个列。
XLGrid看Demo对其的应用了解初步的架构
TXLSheet = class(TComponent)类似于文档,FUsers类似于视图列表
TXLSheet.FSections: array[TXLSector] of TXLSection;//TXLSector = (sCols, sRows, sTitle, sClient);
TXLSection = class(TListSList)
TXLView = class(TWinControl)
TXLGrid = class(TCustomPanel, IXLSheetUser)类似于视图。
一个Grid拥有四个TXLView :ColsView,RowsView,TitleView,ClientView
一个Grid对应一个TXLSheet
TXLSection.PaintRect //4995 行 PaintRect Begin
PaintCells
TXLSection.PaintCell
TXLSheet.Objects[]
PeekCells[]
function TXLSection.GetPeekCell(ACoord: TPoint): TXLCell;
var XLRow: TXLRow;
begin
ACoord := Redirect(ACoord);
Result := Nil; XLRow := TXLRow(Items[ACoord.Y]);
if XLRow <> Nil then Result := TXLCell(XLRow[ACoord.X]);
end;
function TXLSection.GetPeekCell(ACoord: TPoint): TXLCell;
var XLRow: TXLRow;
begin
ACoord := Redirect(ACoord);
Result := Nil; XLRow := TXLRow(Items[ACoord.Y]);
if XLRow <> Nil then Result := TXLCell(XLRow[ACoord.X]);
end;
行模式!!!
TXLRow
TXLView.WMPaint核心DoDraw
TXLEditCell可看作TXLEditInfo的特例,模拟消息
TXLAxis 看作0..1即可