来!做一个 搞怪的 DBGrid(2分)

  • 主题发起人 主题发起人 kinneng
  • 开始时间 开始时间
K

kinneng

Unregistered / Unconfirmed
GUEST, unregistred user!
这两天上来灌水,见到有贴《dbgrid能做出每行每个单元格宽度各不一样的列表吗?要求贴
内所示 3200分急求方法》http://www.delphibbs.com/delphibbs/dispq.asp?lid=3536549

哇塞! 3200分,天价,虽然真正会放分的机会很渺茫,不过题目倒是很有意思,也许有些
人认为做不出来,所以人投了这么多分。

一、
在 Grids.pas 里面,有个函数是取格子的宽度的 GetColWidths,有很多函数靠它来取得
列的宽度,包括绘图部分等等,所以解决它就解决了很多问题。

function TCustomGrid.GetColWidths(Index: Longint): Integer;
begin
if (FColWidths = nil) or (Index >= ColCount) then
Result := DefaultColWidth
else
Result := PIntArray(FColWidths)^[Index + 1];
end;

扩充它为:

function TCustomGrid.GetColWidths(Index, ARow: Longint): Integer;
var
FWidth: Integer;
begin
if (FColWidths = nil) or (Index >= ColCount) then
FWidth := DefaultColWidth
else
FWidth := PIntArray(FColWidths)^[Index + 1];

//新增一个事件,让用户可以重新定义格子的宽度
if Assigned(FGetCellWidthEvent) then
FGetCellWidthEvent(Index, ARow, FWidth);
if FWidth < 0 then FWidth :=0; //避免用户恶搞,保证宽度不小于0
Result := FWidth;
end;

然后,凡是涉及这个函数的地方,一律加上 ARow 参数,具体就几处而已,现在的水费贵,
不灌了。


二、
画格子是在 Paint 过程里面画的,因为不在需要画上规则的垂直线,所以把画垂直线的部
分处理一下:

DrawLines(goHorzLine in Options, goVertLine in Options, LeftCol,
TopRow, [Horz.FixedBoundary, Vert.FixedBoundary, Horz.GridBoundary,
Vert.GridBoundary], LineColor, Color);

StackFree(StrokeList);
StackFree(PointsList);
end;

将这句 goVertLine in Options 改成 False 永远禁止绘制垂直线!

DrawLines(goHorzLine in inherited Options, False, LeftCol,
TopRow, [Horz.FixedBoundary, Vert.FixedBoundary, Horz.GridBoundary,
Vert.GridBoundary], LineColor, Color);

StackFree(StrokeList);
StackFree(PointsList);
end;

垂直线总要画的,我找了个画的地方,在 Paint 的子过程 DrawCells 里面,看到这两句

Where.Left := Where.Right + DrawInfo.Horz.EffectiveLineWidth;
Inc(CurCol);
end;
Where.Top := Where.Bottom + DrawInfo.Vert.EffectiveLineWidth;
Inc(CurRow);

现在加上自己画垂直线的代码,

if (CurCol >0)and(CurRow>0) then
begin
Canvas.MoveTo(Where.Right, Where.Top);
Canvas.LineTo(Where.Right, Where.Bottom);
end;
Where.Left := Where.Right + DrawInfo.Horz.EffectiveLineWidth;
Inc(CurCol);
end;
Where.Top := Where.Bottom + DrawInfo.Vert.EffectiveLineWidth;
Inc(CurRow);

实际上还要加上标题,指示列是否存在的判断代码,这里做实验,就免了,到
此为止,在界面上基本达到要求。

三、
界面上达到要求,但鼠标点击还有问题!有一个 CalcCoordFromPoint 的函数
是做这方面计算的。它的子函数 DoCalc 要修改!

for I := Start to Stop do
begin
Inc(Line, GetExtent(I) + EffectiveLineWidth);
if N < Line then
begin
Result := I;
Exit;
end;
end;

先将 DoCalc 复制一份,改名为 DoCalcY,然后修改 DoCalc 为:

for I := Start to Stop do
begin
Inc(Line, GetColWidths(I,Y) + EffectiveLineWidth);
if N < Line then
begin
Result := I;
Exit;
end;
end;

利用前面修改的 GetColWidths,然后将 CalcCoordFromPoint 函数

if not UseRightToLeftAlignment then
Result.X := DoCalc(DrawInfo.Horz, X, Result.Y)
else
Result.X := DoCalcRightToLeft(DrawInfo.Horz, X, Result.Y);

修改为

Result.Y := DoCalcY(DrawInfo.Vert, Y); //利用原来的函数计算垂直间距
if not UseRightToLeftAlignment then
Result.X := DoCalc(DrawInfo.Horz, X, Result.Y)
else
Result.X := DoCalcRightToLeft(DrawInfo.Horz, X, Result.Y);

这样鼠标点击就不会出现错位。

下载 http://kinneng.icpcn.com/htm/demo.htm

下面还要解决滚动!编辑框的问题,滚动在 Scroll 过程里面修改,而编辑框的
定位主要是修改 BoxRect 函数,不难修改。

改来改去,好像都在修改 Grids.pas 和 DBGrid 无关,但真是这么改就可以
成功的,因为 DBGrid 是 CustomGrid 的扩展版!

无论 Grids.pas 和 DBGrid.pas 都是不应该改的,这里只是做实验,最后把所有
改动,合成为新的独立控件。

到此,我已经解决了大部分问题,看上去简单,但实际真的很复杂,要了解其中
各种函数用途和算法,否则就无从入手,我没空不再搞下去了,也没有搞下去的
价值!即使是想拿来炫耀技术,也不值得花这个时间!
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
618
import
I
I
回复
0
查看
720
import
I
后退
顶部