TGrid行颜色修改后滚动触发访问违规错误的解决咨询
问题分析与解决建议
核心问题原因
- 选中行状态不同步:手动维护
FSelectedRow变量仅通过CellClick更新,无法响应键盘选中、滚动时行状态变化等场景,导致绘制时访问无效行数据。 - Bitmap访问不严谨:直接从
Value中提取TBitmap未做有效性校验,滚动时Grid虚拟行复用可能导致Bitmap已被释放,触发内存访问错误。 - 代码结构不规范:过程内嵌套
begin及变量声明位置易引发变量作用域或初始化问题。
修改步骤
1. 移除手动维护的选中行变量
删除private段的FSelectedRow: Integer;声明,同时简化RejestrCellClick事件:
procedure TZ.RejestrCellClick(const Column: TColumn; const Row: Integer); begin Rejestr.SelectRow(Row); // 移除原FSelectedRow赋值和Repaint调用,Grid选中时会自动重绘 end;
2. 改用Grid自带的选中状态判断
修改RejestrDrawColumnCell和UstawWygladRejestru,通过State参数直接判断选中行:
procedure TZ.RejestrDrawColumnCell(Sender: TObject; const Canvas: TCanvas; const Column: TColumn; const Bounds: TRectF; const Row: Integer; const Value: TValue; const State: TGridDrawStates); begin UstawWygladRejestru(Sender, Canvas, Column, Bounds, Row, Value, State); end; procedure TZ.UstawWygladRejestru(Sender: TObject; const Canvas: TCanvas; const Column: TColumn; const Bounds: TRectF; const Row: Integer; const Value: TValue; const State: TGridDrawStates); var Bitmap: TBitmap; SourceRect: TRectF; begin // 用Grid自带的选中状态判断,避免同步问题 if State.Contains(TGridDrawState.Selected) then Canvas.Fill.Color := TAlphaColors.Bisque else Canvas.Fill.Color := TAlphaColors.Beige; Canvas.FillRect(Bounds, 0, 0, [], 1); if Column is TImageColumn then begin // 严格校验Bitmap有效性,避免访问已释放内存 if Value.IsType<TBitmap> then begin Bitmap := Value.AsType<TBitmap>; if Assigned(Bitmap) and (Bitmap.Width > 0) and (Bitmap.Height > 0) then begin // 使用Bitmap实际尺寸作为源矩形,避免越界访问 SourceRect := RectF(0, 0, Bitmap.Width, Bitmap.Height); Canvas.DrawBitmap(Bitmap, SourceRect, Bounds, 1, True); end; end; end else begin Canvas.Fill.Color := TAlphaColors.Black; Canvas.FillText(Bounds, Value.ToString, False, 1, [], TTextAlign.Leading, TTextAlign.Center); end; end;
3. 可选:复用Grid默认图片绘制逻辑
如果不想手动处理Bitmap,可让Grid用原ImageStyle逻辑绘制图片,彻底避免内存管理问题:
procedure TZ.UstawWygladRejestru(Sender: TObject; const Canvas: TCanvas; const Column: TColumn; const Bounds: TRectF; const Row: Integer; const Value: TValue; const State: TGridDrawStates); var NewState: TGridDrawStates; begin if State.Contains(TGridDrawState.Selected) then Canvas.Fill.Color := TAlphaColors.Bisque else Canvas.Fill.Color := TAlphaColors.Beige; Canvas.FillRect(Bounds, 0, 0, [], 1); if Column is TImageColumn then begin // 移除选中状态,避免默认绘制覆盖自定义背景 NewState := State - [TGridDrawState.Selected]; // 调用Grid默认绘制逻辑处理图片 (Sender as TGrid).DefaultDrawColumnCell(Canvas, Column, Bounds, Row, Value, NewState); end else begin Canvas.Fill.Color := TAlphaColors.Black; Canvas.FillText(Bounds, Value.ToString, False, 1, [], TTextAlign.Leading, TTextAlign.Center); end; end;
额外注意事项
- 确保Grid的
RowSelect属性设为True,保证选中行状态正确传递。 - 避免在
DrawColumnCell中执行耗时操作,防止滚动卡顿。
内容的提问来源于stack exchange,提问作者Woj Tas
相关产品推荐
相关产品推荐

