我想创建一个字符串网格来显示某种垂直光标以突出显示当前选定的列。因此,在MouseDown中我调用setCurPos,然后调用InvalidateCol使当前列无效。这称为DrawCell。 DrawCell将光标绘制在当前列上。
问题在于:如果我在网格中有更多行,那么它可以显示其中一些不可见(当然),因此网格的垂直滚动条将自动出现。当我向下滚动以查看网格底部的行时,光标不会在这些行中绘制。看起来光标未绘制的底行数(现在在屏幕上可见)与网格顶部不可见行的数量成正比。
如果我最小化并恢复应用程序,光标就会很好地绘制。所以,很明显invalidateColumn()不起作用。
procedure TmyGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
VAR aCol, aRow: Integer;
begin
MouseToCell(X, Y, ACol, ARow);
...
inherited MouseDown(Button, Shift, X, Y);
CursorPosFocus:= ACol;
end;
procedure TmyGrid.setCurPos(CONST NewColumn: Integer);
VAR OldPos: Integer;
begin
...
OldPos:= CursorPos;
FCursorPos:= NewColumn;
...
//- This is not working:
//InvalidateCol(OldPos);
//InvalidateCol(NewColumn);
//Update;
//- THIS WORKS:
InvalidateGrid;
end;
procedure TmyGrid.DrawCell(ACol, ARow: integer; ARect: TRect; AState: TGridDrawState);
Var TempRect: TRect;
begin
inherited;
...
{DRAW CURSOR}
if CursorPos= ACol then
begin
TempRect.Top := 0;
TempRect.Left := ARect.Left;
TempRect.Right := ARect.Right;
TempRect.Bottom:= ClientHeight-2;
Frame3D(Canvas, TempRect, $909090, $808080, 1);
end;
end;
Delphi 7,Win XP
答案 0 :(得分:5)
你没有做错任何事,你刚刚陷入了Delphi 4 VCL中的VCL网格实现中的一个错误(我之前没有任何早期的CD可以检查,但它甚至可能已经在16位Delphi VCL已经存在并且仍在Delphi 2009中。
使整个行或列无效的两种方法都是通过计算传递给内部InvalidateRect()
方法的单元格区域来实现的。该区域始终以列/行0开头,并扩展到第一个完全不可见的行/列。很明显,这只能在未注册的客户区域正常工作。代码应该做的是对最后一列/行无效,让InvalidateRect()
帮助器中的代码确定哪些单元格确实可见,并计算需要从中无效的客户区域。
由于您正在编写自己的类,因此您可以轻松地实现自己的方法来使无效的单元格无效;多年前我做了同样的事情,还有更多的方法来使多列,多行和整个单元格块无效。由于InvalidateRect()
是私有的(在那里也很好思考),您需要使用具有相同名称的Windows API函数,并使用CellRect()
或BoxRect()
方法计算要使其无效的矩形。
虽然InvalidateGrid()
对您有用,但它实际上是一种大锤 - 它使整个网格无效,我认为当您开始使用InvalidateCol()
时,这不是您想要的。
对于您的实验,您应该可以轻松地看到每个细胞的绘画周期。导致细胞的背景颜色随每次更新而改变,这是检查您是否真的只进行最小屏幕重绘的简单方法。像
这样的东西StringGrid1.Canvas.Brush.Color := RGB(Random(256), Random(256), Random(256));
StringGrid1.Canvas.FillRect(Rect);
OnDrawCell
事件处理程序中的工作正常。