我想创建一个字符串网格来显示某种垂直光标以突出显示当前选定的列。因此,在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
你没有做错什么,你刚刚被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
事件处理程序工作正常。