在Delphi TStringGrid跨列绘制条形块时如何显示超长文本
解决方案:TStringGrid跨列绘制超长文本避免被覆盖
方法一:利用OnPaint事件(最可靠)
TStringGrid的OnPaint事件会在所有单元格的OnDrawCell执行完成后触发,此时绘制的文本不会被后续的单元格绘制操作覆盖。具体步骤如下:
- 修改
OnDrawCell事件,仅处理背景和边框,移除原有的跨列文本绘制代码,并禁止默认文本绘制:
procedure TFVoDGraphicalPlannerForm.GRDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); begin // 处理第2行5-10列的背景与边框 if (ARow = 2) and (ACol >= 5) and (ACol <= 10) then begin GR.Canvas.Brush.Color := clBtnFace; GR.Canvas.FillRect(Rect); // 绘制左边界(仅第5列) if ACol = 5 then begin GR.Canvas.Pen.Width := 1; GR.Canvas.Pen.Color := clBlack; GR.Canvas.MoveTo(Rect.Left - 1, Rect.Top); GR.Canvas.LineTo(Rect.Left - 1, Rect.Bottom); end; // 绘制右边界(仅第10列) if ACol = 10 then begin GR.Canvas.Pen.Width := 1; GR.Canvas.Pen.Color := clBlack; GR.Canvas.MoveTo(Rect.Right - 1, Rect.Top); GR.Canvas.LineTo(Rect.Right - 1, Rect.Bottom); end; // 绘制上下边界(所有5-10列) GR.Canvas.Pen.Width := 1; GR.Canvas.Pen.Color := clBlack; GR.Canvas.MoveTo(Rect.Left, Rect.Top - 1); GR.Canvas.LineTo(Rect.Right, Rect.Top - 1); GR.Canvas.MoveTo(Rect.Left, Rect.Bottom - 1); GR.Canvas.LineTo(Rect.Right, Rect.Bottom - 1); // 跳过默认文本绘制,避免干扰自定义内容 Exit; end; // 其他单元格保留默认绘制逻辑 GR.DefaultDrawCell(ACol, ARow, Rect, State); end;
- 为TStringGrid添加
OnPaint事件,在其中计算跨列的整体区域并绘制文本:
procedure TFVoDGraphicalPlannerForm.GRPaint(Sender: TObject); var FTotalRect: TRect; FLeftCellRect, FRightCellRect: TRect; FTxtFormat: TTextFormat; FTempStr: string; begin // 计算第2行5-10列的整体显示区域 FLeftCellRect := GR.CellRect(5, 2); FRightCellRect := GR.CellRect(10, 2); FTotalRect.Left := FLeftCellRect.Left + 5; // 保留原有的左边距 FTotalRect.Top := FLeftCellRect.Top; FTotalRect.Right := FRightCellRect.Right; FTotalRect.Bottom := FLeftCellRect.Bottom; // 设置文本样式 GR.Canvas.Font.Style := [fsBold]; GR.Canvas.Font.Color := $009A9A9A; GR.Canvas.Font.Size := 14; // 绘制跨列文本 FTempStr := 'Unusually long description that spans multiple columns and goes on and on...'; FTxtFormat := [tfTop, tfLeft]; GR.Canvas.TextRect(FTotalRect, FTempStr, FTxtFormat); end;
方法二:在最后一列的DrawCell中绘制
TStringGrid默认按行从上到下、每行内从左到右的顺序绘制单元格,因此可以在目标区域的最后一列(第10列)中绘制跨列文本,此时不会被后续单元格覆盖:
修改OnDrawCell事件,将文本绘制逻辑移至第10列的处理分支中:
procedure TFVoDGraphicalPlannerForm.GRDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); var FTotalRect: TRect; FTxtFormat: TTextFormat; FTempStr: string; begin // 处理第2行5-10列的背景与边框 if (ARow = 2) and (ACol >= 5) and (ACol <= 10) then begin GR.Canvas.Brush.Color := clBtnFace; GR.Canvas.FillRect(Rect); // 绘制左边界(仅第5列) if ACol = 5 then begin GR.Canvas.Pen.Width := 1; GR.Canvas.Pen.Color := clBlack; GR.Canvas.MoveTo(Rect.Left - 1, Rect.Top); GR.Canvas.LineTo(Rect.Left - 1, Rect.Bottom); end; // 绘制右边界+跨列文本(仅第10列) if ACol = 10 then begin GR.Canvas.Pen.Width := 1; GR.Canvas.Pen.Color := clBlack; GR.Canvas.MoveTo(Rect.Right - 1, Rect.Top); GR.Canvas.LineTo(Rect.Right - 1, Rect.Bottom); // 计算跨列文本的显示区域 FTotalRect.Left := GR.CellRect(5, 2).Left + 5; FTotalRect.Top := GR.CellRect(5, 2).Top; FTotalRect.Right := Rect.Right; FTotalRect.Bottom := Rect.Bottom; // 设置文本样式并绘制 GR.Canvas.Font.Style := [fsBold]; GR.Canvas.Font.Color := $009A9A9A; GR.Canvas.Font.Size := 14; FTempStr := 'Unusually long description that spans multiple columns and goes on and on...'; FTxtFormat := [tfTop, tfLeft]; GR.Canvas.TextRect(FTotalRect, FTempStr, FTxtFormat); end; // 绘制上下边界(所有5-10列) GR.Canvas.Pen.Width := 1; GR.Canvas.Pen.Color := clBlack; GR.Canvas.MoveTo(Rect.Left, Rect.Top - 1); GR.Canvas.LineTo(Rect.Right, Rect.Top - 1); GR.Canvas.MoveTo(Rect.Left, Rect.Bottom - 1); GR.Canvas.LineTo(Rect.Right, Rect.Bottom - 1); // 跳过默认文本绘制 Exit; end; // 其他单元格保留默认绘制逻辑 GR.DefaultDrawCell(ACol, ARow, Rect, State); end;
原理说明
- 方法一通过
OnPaint事件确保文本在所有单元格绘制完成后再渲染,彻底避免覆盖问题,适用于所有场景。 - 方法二依赖TStringGrid默认的单元格绘制顺序,实现简单,但如果列的显示顺序被修改(如用户拖动列排序),可能会失效。
内容的提问来源于stack exchange,提问作者TomR
相关产品推荐
相关产品推荐

