Delphi FMX StringGrid 枠線


gai  2025-03-07 15:36:32  No: 151865  IP: [192.*.*.*]

AndroidアプリでTStringGridを使っているんですが、VCLみたいにデフォルト枠線がなく、OnDrawCellで枠線をRect範囲で書くようにしているんですが、どうしても隙間や重なりが気になります。
VCLのような見た目を作るにはどうすればいいんですか?

編集    削除
gari  2025-03-07 17:30:48  No: 151866  IP: [192.*.*.*]

【追記】
解決したいことを箇条書きに
・FMXのTStringGridの枠線をVCLのTStringGridのようにする
 →おそらく各StringColumのスクロールバーの部分で各セルの隙間が出来ている

実際のコードはこれです
procedure TFM.grdd1DrawColumnCell(Sender: TObject; const Canvas: TCanvas;
  const Column: TColumn; const Bounds: TRectF; const Row: Integer;
  const Value: TValue; const State: TGridDrawStates);
var
  drawRect: TRectF;
begin
  drawRect.Top    := Bounds.Top-3;
  drawRect.Left   := Bounds.Left;
  drawRect.Bottom := Bounds.Bottom+3;
  drawRect.Right  := Bounds.Right+4;

  grdData.Canvas.Stroke.Kind := TBrushKind.Solid;
  grdData.Canvas.Stroke.Color := TAlphaColors.Black;
  grdData.Canvas.Stroke.Thickness := 1;
  grdData.Canvas.DrawRect(drawRect, 0, 0, [], 1);
end;

編集    削除
igy  2025-03-08 10:32:55  No: 151868  IP: [192.*.*.*]

試していませんが、OnDrawColumnCellイベントではなく、
OnDrawColumnBackgroundイベントで描画した場合は、どうなりますか?

編集    削除
gari  2025-03-10 09:40:52  No: 151870  IP: [192.*.*.*]

確認しました。
上記のコードのままイベントハンドラをOnDrawColumnBackgroundイベントにした場合は、各セルの縦線は表示されなくなり、横線のみ現れ(rowcountが1以降)、それも一つ前のRowCountの下線と追加したセルの上線に追加されています。

編集    削除
igy  2025-03-10 11:06:34  No: 151871  IP: [192.*.*.*]

DrawRect ではなく、DrawLine を使って、セルの下側と右側とかに描画してみるのは、いかがですか?

編集    削除
gari  2025-03-10 21:40:23  No: 151872  IP: [192.*.*.*]

DrawLine試しましたが、うまくいきそうではありますが、各カラムセルwidthが異なる場合やTPointFを取得するのが、なかなか柔軟性に欠ける感じがしました。
もしよろしければ、DrawLineでのコードをご教授お願いします。

以下、テスト用で使ったコードです
procedure TForm1.StringGrid1DrawColumnCell(Sender: TObject;
  const Canvas: TCanvas; const Column: TColumn; const Bounds: TRectF;
  const Row: Integer; const Value: TValue; const State: TGridDrawStates);
var
  CellWidth, CellHeight: Integer;
  Rows, Columns: Integer;
  I, J: Integer;
  StartPoint, EndPoint: TPointF;
begin
  // セルの数とサイズを設定
  Rows := StringGrid1.RowCount;          // 行数
  Columns := StringGrid1.ColumnCount;    // 列数
  CellWidth := 100; // 各セルの幅
  CellHeight := 50; // 各セルの高さ

  // グリッドのセルに対して線を描画
  for I := 0 to Rows do
  begin
    // 水平線を描画
    StartPoint := TPointF.Create(0, I * CellHeight);
    EndPoint := TPointF.Create(Columns * CellWidth, I * CellHeight);
    Canvas.DrawLine(StartPoint, EndPoint, 1, TStrokeBrush.Create(TBrushKind.Solid,TAlphaColorrec.Black)); //黒い線
  end;

  for J := 0 to Columns do
  begin
    // 垂直線を描画
    StartPoint := TPointF.Create(J * CellWidth, 0);
    EndPoint := TPointF.Create(J * CellWidth, Rows * CellHeight);
    Canvas.DrawLine(StartPoint, EndPoint, 1, TStrokeBrush.Create(TBrushKind.Solid,TAlphaColorRec.Black)); //黒い線
  end;
end;

編集    削除
igy  2025-03-10 21:58:06  No: 151873  IP: [192.*.*.*]

Androidではなく、Windowsで試したのですが・・

const
    TEST_COL = 20;
    TEST_ROW = 80;

// FormCreate
procedure TForm1.FormCreate(Sender: TObject);
var
    sCol: TStringColumn;
    c, r: Integer;
begin
    // 線と文字列の描画は、OnDrawColumnCellイベント・OnDrawColumnBackgroundイベントにて行うので、
    // いくつか設定を変更。
    StringGrid1.DefaultDrawing := False;
    StringGrid1.Options := StringGrid1.Options - [TGridOption.ColLines, TGridOption.RowLines];

    // StringGrid初期値設定
    with StringGrid1 do
    begin
        BeginUpdate;
        for c := 1 to TEST_COL do
        begin
            sCol := TStringColumn.Create(StringGrid1);
            sCol.Name := 'col' + IntToStr(c);
            sCol.Header := 'テスト' + IntToStr(c);
            sCol.Width := 80;
            AddObject(sCol);
        end;
        EndUpdate;

        RowCount := TEST_ROW;

        for r := 0 to RowCount - 1 do
            for c := 0 to ColumnCount - 1 do
                Cells[c, r] := Format('[%d, %d]', [c, r]);
    end;
end;

// StringGrid1:DrawColumnBackgroundイベント
procedure TForm1.StringGrid1DrawColumnBackground(Sender: TObject; const Canvas: TCanvas; const Column: TColumn;
  const Bounds: TRectF; const Row: Integer; const Value: TValue; const State: TGridDrawStates);
begin
    // 背景描画
    if (Row mod 2) = 0 then
        Canvas.Fill.Color := TAlphaColorRec.White
    else
        Canvas.Fill.Color := TAlphaColorRec.Whitesmoke;
    Canvas.FillRect(Bounds, 0, 0, AllCorners, 1.0, TCornerType.Round);

    // 枠線描画
      Canvas.Stroke.Kind  := TBrushKind.Solid;
    Canvas.Stroke.Color := TAlphaColorRec.Black;
    Canvas.Stroke.Thickness := 1.0;
    // 縦線
    Canvas.DrawLine(PointF(Bounds.Right, Bounds.Top), PointF(Bounds.Right, Bounds.Bottom), 1.0);
    // 横線
    if (Row mod 5) = 4 then
        Canvas.Stroke.Color := TAlphaColorRec.Red;    // 5行おきに線の色を赤に
    Canvas.DrawLine(PointF(Bounds.Left, Bounds.Bottom), PointF(Bounds.Right, Bounds.Bottom), 1.0);
end;

// StringGrid1:DrawColumnCellイベント
procedure TForm1.StringGrid1DrawColumnCell(Sender: TObject; const Canvas: TCanvas; const Column: TColumn;
  const Bounds: TRectF; const Row: Integer; const Value: TValue; const State: TGridDrawStates);
begin
    // 文字描画
      Canvas.Fill.Color := TAlphaColorRec.Blue;
    Canvas.FillText(Bounds, Trim(Value.AsString), True, 1.0, [], TTextAlign.Center, TTextAlign.Center);
end;

編集    削除
gari  2025-03-10 23:10:52  No: 151874  IP: [192.*.*.*]

ありがとうございます。
実際にコードを試してみましたが、できそうです。後はTStringGridの枠事態とヘッダーの部分に枠線をつければ、VCL同様のUIになれそうです。
各セル座標の取得で、PointF(Bounds.Left,Bounds.Bottom)のようにできるのは、盲点でした。
非常にためになるコードを書いてくださりありがとうございます。

編集    削除