【问题标题】:Stringgrid wordwrap displays text twiceStringgrid 自动换行显示文本两次
【发布时间】:2017-10-09 16:41:14
【问题描述】:

我想在字符串网格单元格中以自动换行格式显示一个长字符串,并找到了以下代码:

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
//enable wordwrap in cells
var
  S: String;
  drawrect :trect;
begin
  stringgrid1.Canvas.FillRect (Rect);
  S:= (Sender As TStringgrid).Cells [ACol, ARow ];
  If Length(S) > 0 Then Begin
    drawrect := rect;
    DrawText((Sender As TStringgrid).canvas.handle,
              Pchar(S), Length(S), drawrect,
              dt_calcrect or dt_wordbreak or dt_left );
    If (drawrect.bottom - drawrect.top) >
       (Sender As TStringgrid).RowHeights[Arow]
    Then
      (Sender As TStringgrid).RowHeights[Arow] :=
         (drawrect.bottom - drawrect.top)
      // changing the row height fires the event again!
    Else Begin
      drawrect.Right := rect.right;

      (Sender As TStringgrid).canvas.fillrect( drawrect );
      DrawText((Sender As TStringgrid).canvas.handle,
                Pchar(S), Length(S), drawrect,
                dt_wordbreak or dt_left);
    End;
  End;
end;

自动换行有效,但单元格同时显示原始文本和换行文本。我假设因为这是一个 onDrawCell 事件,原始文本已经被绘制,我会用第一行代码(stringgrid1.canvas.fillrect(rect) 删除它,但这对显示没有影响。我是什么不见了?

【问题讨论】:

  • 不要从绘图事件中设置行高。这又会再次触发绘图事件。
  • 听起来您仍然启用了DefaultDrawing。适当的做法是禁用它,但您也负责 all 绘图。
  • @Victoria 由于 stringgrid 不执行自动换行,所以我必须使用 onDrawCell 事件来修改单元格大小并显示文本。
  • 不,您不必这样做。实际上,你不应该那样做。实际上是你设置了单元格文本,所以进行测量并在那里设置行高(TStringGrid 是旧的,不是灵活的控制)。而且,如果您允许,也可以在调整列大小时(但这需要网格类拦截)。
  • @JerryDodge 我想避免自己绘制整个字符串网格。由于此代码在初始绘图后执行,因此我期望填充矩形。覆盖文本原始显示,然后重新绘制包装的文本。

标签: delphi vcl tstringgrid


【解决方案1】:

...会用第一行代码删除它 (stringgrid1.canvas.fillrect(rect),但这对 显示

这是因为您在调用FillRect() f.ex 之前没有选择Brush.Style(也可能还有Brush.Color)。

  stringgrid1.canvas.Brush.Style := bsSolid; // add this line
  stringgrid1.canvas.Brush.Color := clWhite; // add this line
  stringgrid1.Canvas.FillRect (Rect);

您会注意到单元格左边缘的默认绘图有一些残留物(在下图中不可见,我已经修复了它们)。这是因为TStringGrid 在内部将单元格绘图偏移了 4 个像素。要改变这一点,您需要使用 -4 抵消 Rect 参数并使用 +4 增加宽度,同样在调用 FillRect() 之前。

在上述更改之后,网格看起来非常平坦和暗淡(在图像中,我已经在第二个网格中添加了颜色)。要恢复标题列和标题行的一些颜色差异,您需要用不同的Brush.Color 处理带有gdFixed in State 的单元格。 gdSelected in State 的单元格也是如此。

如果你取消DefaultDrawing,以上是你还需要做的。第二个网格和随附的代码演示了这一点。请注意,代码还包括在结束前gdFocused in State 时对DrawFocusRect 的调用。

请注意,我将所有这些 Sender as TStringGrid 替换为本地 grid 变量。

procedure TForm4.StringGrid2DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect;
  State: TGridDrawState);
var
  grid: TStringGrid;
  S: String;
  drawrect: TRect;
  bgFill: TColor;
begin
  grid := Sender as TStringGrid;

  if gdFixed in State then
    bgFill := $FFF8F8
  else
  if gdSelected in State then
    bgFill := $FFF0D0
  else
    bgFill := clWhite;

  grid.Canvas.Brush.Color := bgFill;
  grid.canvas.Brush.Style := bsSolid;
  grid.canvas.fillrect(Rect);

  S := grid.Cells[ACol, ARow];
  if Length(S) > 0 then
  begin
    drawrect := Rect;
    drawrect.Inflate(-4 , 0);
    DrawText(grid.canvas.handle, Pchar(S), Length(S), drawrect,
      dt_calcrect or dt_wordbreak or dt_left);
    If (drawrect.bottom - drawrect.top) > grid.RowHeights[ARow] then
      grid.RowHeights[ARow] := (drawrect.bottom - drawrect.top+2)
      // changing the row height fires the event again!
    else
    begin
      drawrect.Right := Rect.Right;

//      grid.canvas.fillrect(drawrect);
      DrawText(grid.canvas.handle, Pchar(S), Length(S), drawrect,
        dt_wordbreak or dt_left);
    end;
  end;

  if gdFocused in State then
    grid.Canvas.DrawFocusRect(Rect);
end;

第三个网格展示了最简单和 IMO 最好的解决方案,即完全跳过 TStringGrid 并改用 TDrawGrid。您必须将要在网格中显示的数据单独保存在某处。我定义了一个数组:s_arr: array of array of string;

在这种情况下,您可以将DefaultDrawing 保持打开状态,因为TDrawGrid 在默认绘制期间不绘制任何文本,内容绘制仅在OnDrawCell 事件中进行。

procedure TForm4.DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect;
  State: TGridDrawState);
var
  S: string;
  grid: TDrawGrid;
  drawrect: TRect;
begin
  grid := Sender as TDrawGrid;
  S := s_arr[ACol, ARow];
  If Length(S) > 0 Then
  Begin
    drawrect := Rect;
    drawrect.Inflate(-4 , 0);
    DrawText(grid.canvas.handle, Pchar(S), Length(S), drawrect,
      dt_calcrect or dt_wordbreak or dt_left);
    If (drawrect.bottom - drawrect.top) > grid.RowHeights[ARow] Then
      grid.RowHeights[ARow] := (drawrect.bottom - drawrect.top + 2)
      // changing the row height fires the event again!
    Else
    Begin
      drawrect.Right := Rect.Right;

      grid.canvas.fillrect(drawrect);
      DrawText(grid.canvas.handle, Pchar(S), Length(S), drawrect, dt_wordbreak or dt_left);
    End;
  End;
end;

保持DefaultDrawing 开启,所有这些与主题相关的功能都是由网格本身绘制的,我们只在顶部绘制文本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-16
    相关资源
    最近更新 更多