Delphi 10 TDrawGrid – How do I get rows to refresh properly?
使用 Delphi 10.2 Tokyo。
我使用 DrawCell 方法使一行中的所有列与所选单元格的颜色相同。这允许我让用户单击不同的单元格,但仍显示”选定”行。
这使用 OnSelectCell 方法使原始行和新选择的行无效。多年来一直使用这种方法。
如果我有一个带有水平滚动条的网格,则当向右滚动并且用户单击单元格时,该网格不会正确绘制。
下面是一个使用 TDrawGrid 和 OnDrawCell 事件和 OnSelectCell 事件的简单示例:
表格 (DFM) 代码:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
object Form1: TForm1
Left = 0 Top = 0 Caption = ‘Form1’ ClientHeight = 299 ClientWidth = 635 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = –11 Font.Name = ‘Tahoma’ Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object DrawGrid1: TDrawGrid Left = 0 Top = 0 Width = 635 Height = 299 Align = alClient Color = clWhite ColCount = 15 DefaultColWidth = 65 DefaultRowHeight = 48 DefaultDrawing = False DrawingStyle = gdsGradient RowCount = 12 GradientEndColor = clBtnFace GradientStartColor = clBtnFace Options = [goThumbTracking] ParentShowHint = False ShowHint = True TabOrder = 0 OnDrawCell = DrawGrid1DrawCell OnSelectCell = DrawGrid1SelectCell ColWidths = ( 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65) RowHeights = ( 48 48 48 48 48 48 48 48 48 48 48 48) end end |
单位 (PAS) 代码:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
unit Unit1;
interface uses type TForm1 = class(TForm) var implementation {$R *.dfm} procedure TForm1.DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); MyCanvas.Font.Name := ‘Arial’; // drawgrid uses Tahoma 8pt as its default font, not Arial if (ARow = 0) then begin MyCanvas.Font.Color := clblack; // clGray; MyRect.Top := MyRect.Top + 2; MyCanvas.Font.Style := MyCanvas.Font.Style – [fsBold]; MyCanvas.FillRect(Rect); // other cell drawing of text happens after here procedure TForm1.DrawGrid1SelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); end. |
运行程序。
单击水平滚动条,使第 14 列可见。
单击第 2 行中的第 13 列。
单击第 3 行中的第 12 列。
注意到真正混乱的选择模式了吗?
这是结果的屏幕截图:
理想情况下,应该有一排蓝色单元格,而不是乱七八糟的。第 3 行应该是纯蓝色。
在 OnSelectCell 方法中调用 DrawGrid1.Refresh 甚至无法修复它。
关于如何使它真正起作用的任何想法?我不能对这个网格使用 RowSelect。
干杯!
TJ
- 请参阅 qc.embarcadero.com/wc/qcmain.aspx?d=81060 这是一个自 delphi 开始以来就存在的错误
除了不必要的闪烁之外,您的代码似乎没有任何错误。这可以通过使用 OnDrawCell 事件的 State 来解决。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
procedure TForm1.DrawGrid1DrawCell(Sender: TObject; ….
var MyCanvas : TCanvas; str : string; MyRect : TRect; begin MyCanvas := TDrawGrid(Sender).Canvas; if gdFixed in State then begin if (ARow = 0) then begin |
错误在 TCustomGrid 的 InvalidateRow 中,它不考虑可能的滚动。列方式相同。
您可以使用受保护的 BoxRect 方法,该方法使用 GridRectToScreenRect(私有)方法将单元格位置转换为屏幕坐标。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
procedure TForm1.DrawGrid1SelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean);
var Grid: TDrawGrid; GR, R: TRect; begin Grid := Sender as TDrawGrid; if ARow = Grid.Row then Exit; GR.Left := Grid.LeftCol; R := TGridCracker(Grid).BoxRect(GR.Left, GR.Top, GR.Right, GR.Bottom); GR.Top := ARow; R := TGridCracker(Grid).BoxRect(GR.Left, GR.Top, GR.Right, GR.Bottom); |
这是由于 VCL TCustomGrid.InvalidateRow(和 TCustomGrid.InvalidateCol)例程中的一个错误:
1
2 3 4 5 6 7 8 9 10 11 |
procedure TCustomGrid.InvalidateRow(ARow: Longint);
var Rect: TGridRect; begin if not HandleAllocated then Exit; Rect.Top := ARow; Rect.Left := 0; // this should be Rect.Left:=LeftCol; –> index of the first column in the scrollable region that is visible Rect.Bottom := ARow; Rect.Right := VisibleColCount+1; InvalidateRect(Rect); end; |
解决此问题的方法:
1
2 3 4 5 6 7 8 9 10 11 12 |
type TGridCracker = class(TDrawGrid)
protected procedure InvalidateRow(ARow: Longint); end; procedure TGridCracker.InvalidateRow(ARow: Integer); |
或
1
2 3 |
for i := LeftCol to LeftCol+VisibleColCount do // this will invalidate only visible cells
InvalidateCell(i, ARow); end; |
来源:https://www.codenong.com/51368662/