3

最初の質問:

表示されていない stringgrid の部分をどのように呼び出しますか? 表示するにはスクロールする必要があります。
例:
stringgrid には 20 行ありますが、一度に表示できるのは 10 行だけです。他の 10 を表示するには、スクロールする必要があります。

2 番目の質問:

これはおそらく正しい方法ではないことを知っているので、いくつかの指針をいただければ幸いです。
固定行が 1 つの文字列グリッドがあります。実行時に ColorButtons を追加します。そのため、1 つの列にボタンを配置します。このボタンを使用して、行を「挿入/削除」します。すべてのグリッドが「可視」部分にある限り、これはうまく機能します。新しい行を「挿入」してボタンを「非表示」部分に移動すると、問題が発生します。次に、最後のボタンが Cell[0,0] に描画されます。「隠れた」部分の他のボタンは正しく描画されます。なぜこれが起こるのか分かりますか?OnDraw メソッドでこの問題を管理する方法を見つける必要がありますか、またはこれを行うためのより良い (正しい) 方法はありますか?

コード:

procedure Tform1.addButton(Grid : TStringGrid; ACol : Integer; ARow : Integer);
var
  bt : TColorButton;
  Rect : TRect;
  index : Integer;
begin
    Rect := Grid.CellRect(ACol,ARow);
    bt := TColorButton.Create(Grid);
    bt.Parent := Grid;
    bt.BackColor := clCream;
    bt.Font.Size := 14;
    bt.Width := 50;
    bt.Top := Rect.Top;
    bt.Left := Rect.Left;
    bt.Caption := '+';
    bt.Name := 'bt'+IntToStr(ARow);
    index := Grid.ComponentCount-1;
    bt :=(Grid.Components[index] as TColorButton);
    Grid.Objects[ACol,ARow] := Grid.Components[index];
    bt.OnMouseUp := Grid.OnMouseUp;
    bt.OnMouseMove := Grid.OnMouseMove;
    bt.Visible := true;
end;

procedure MoveRowPlus(Grid : TStringGrid; Arow : Integer; stRow : Integer);
var
  r, index : Integer;
  bt : TColorButton;
  Rect : TRect;
begin
  Grid.RowCount := Grid.RowCount+stRow;

  for r := Grid.RowCount - 1 downto ARow+stRow do
    begin
      Grid.Rows[r] := Grid.Rows[r-StRow];
    end;

  index := Grid.ComponentCount-1;
  for r := Grid.RowCount - 1 downto ARow+stRow do
    begin
      bt :=(Grid.Components[index] as TColorButton);
      Rect := Grid.CellRect(10,r);
      bt.Top := Rect.Top;
      bt.Left := Rect.Left;
      Grid.Objects[10,r] := Grid.Components[index];
      dec(index);
    end;
      for r := ARow to (ARow +stRow-1) do
        begin
          Grid.Rows[r].Clear;
        end;  
end;

procedure MoveRowMinus(Grid : TStringGrid; Arow : Integer; stRow : Integer);
var
  r, index : Integer;
  bt : TColorButton;
  Rect : TRect;
begin

  for r := ARow to Grid.RowCount-stRow-1 do
    begin
      Grid.Rows[r] := Grid.Rows[r+StRow];
    end;

  index := ARow-1;
  for r := ARow to Grid.RowCount-stRow-1 do
    begin
      Rect := Grid.CellRect(10,r);
      bt :=(Grid.Components[index] as TColorButton);
      bt.Top := Rect.Top;
      bt.Left := Rect.Left;
      Grid.Objects[10,r] := Grid.Components[index];
      bt.Visible := true;
      inc(index);
    end;

  for r := Grid.RowCount-stRow to Grid.RowCount-1 do
    begin
      Grid.Rows[r].Clear;
    end;
  Grid.RowCount := Grid.RowCount-stRow;
end;
4

1 に答える 1

5
  1. VisibleRowCount可視部分にはとプロパティが存在しVisibleColCountます。TGridAxisDrawInfoレコード タイプは、可視部分にBoundaryという名前を付け、すべての部分をまとめてExtentという名前を付けます(またはその逆、私は覚えていません)。そのため、文字列グリッドの非表示部分の VCL 宣言名による特定はありません。見えない部分だけです。

  2. 論理的な誤りを犯していると思います。グリッドをスクロールしてもボタンは移動しません。移動したように見えるかもしれませんが、これは への内部呼び出しによってデバイス コンテキストの内容が移動した結果にすぎませんScrollWindow。文字列グリッド コンポーネントのスクロール バーはカスタムで追加され、たとえば a のようには機能しませんTScrollBox

    実際にある場所にすべてのボタンを常に表示するには、OnTopLeftChangedイベントで文字列グリッドを再描画します。

    procedure TForm1.StringGrid1TopLeftChanged(Sender: TObject);
    begin
      StringGrid1.Repaint;
    end;
    

    すべての行の行の高さと文字列グリッドの高さが変わらない場合は、すべてのボタンを 1 回だけ作成してそのままにしておくだけで十分です。これは、すべてのボタンが行に「添付」されていないことを意味し、それらをObjectsプロパティに格納しても意味がなくなります。TopRowボタンが押されると、グリッド内の最初に表示されるスクロール可能な行のインデックスを指定する文字列グリッドのプロパティと組み合わせて、ボタンの位置から目的の行インデックスを計算するだけです。

    アンカーなどによってグリッドのサイズを変更できる場合は、親の OnResize イベントでボタン数を更新します。また、文字列グリッドの行数が最大表示行数より少なくなる可能性がある場合は、(表示) ボタン数も更新します。

    さらに回答が必要な場合は、質問を更新し、グリッドやボタンとの相互作用によりルーチンがどのように呼び出されるMoveRowPlusかを説明してください。MoveRowMinus

    CellRect間違った座標を指定することについて: これはCellRect、完全な (または部分的な) 可視セルでのみ機能するためです。ドキュメントを引用するには:

    指定されたセルが表示されていない場合CellRectは、空の四角形を返します。


OPのコメントによる追加

次のコードはあなたが望むことをすると思います。すべてのボタンの元の行インデックスは、Tagプロパティに格納されます。

unit Unit1;

interface

uses
  Windows, Classes, Controls, Forms, StdCtrls, Grids;

type
  TForm1 = class(TForm)
    Grid: TStringGrid;
    procedure GridTopLeftChanged(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FPrevTopRow: Integer;
    procedure CreateGridButtons(ACol: Integer);
    procedure GridButtonClick(Sender: TObject);
    procedure RearrangeGridButtons;
    function GetInsertRowCount(ARow: Integer): Integer;
    function GridButtonToRow(AButton: TButton): Integer;
    procedure MoveGridButtons(ButtonIndex, ARowCount: Integer);
  end;

implementation

{$R *.dfm}

type
  TStringGridAccess = class(TStringGrid);

procedure TForm1.FormCreate(Sender: TObject);
begin
  FPrevTopRow := Grid.TopRow;
  CreateGridButtons(2);
end;

procedure TForm1.CreateGridButtons(ACol: Integer);
var
  R: TRect;
  I: Integer;
  Button: TButton;
begin
  R := Grid.CellRect(ACol, Grid.FixedRows);
  Inc(R.Right, Grid.GridLineWidth);
  Inc(R.Bottom, Grid.GridLineWidth);
  for I := Grid.FixedRows to Grid.RowCount - 1 do
  begin
    Button := TButton.Create(Grid);
    Button.BoundsRect := R;
    Button.Caption := '+';
    Button.Tag := I;
    Button.ControlStyle := [csClickEvents];
    Button.OnClick := GridButtonClick;
    Button.Parent := Grid;
    Grid.Objects[0, I] := Button;
    OffsetRect(R, 0, Grid.DefaultRowHeight + Grid.GridLineWidth);
  end;
end;

procedure TForm1.GridButtonClick(Sender: TObject);
var
  Button: TButton absolute Sender;
  N: Integer;
  I: Integer;
begin
  N := GetInsertRowCount(Button.Tag);
  if Button.Caption = '+' then
  begin
    Button.Caption := '-';
    Grid.RowCount := Grid.RowCount + N;
    for I := 1 to N do
      TStringGridAccess(Grid).MoveRow(Grid.RowCount - 1,
        GridButtonToRow(Button) + 1);
    MoveGridButtons(Button.Tag, N);
  end
  else
  begin
    Button.Caption := '+';
    for I := 1 to N do
      TStringGridAccess(Grid).MoveRow(GridButtonToRow(Button) + 1,
        Grid.RowCount - 1);
    Grid.RowCount := Grid.RowCount - N;
    MoveGridButtons(Button.Tag, -N);
  end;
end;

procedure TForm1.GridTopLeftChanged(Sender: TObject);
begin
  RearrangeGridButtons;
  FPrevTopRow := Grid.TopRow;
end;

procedure TForm1.RearrangeGridButtons;
var
  I: Integer;
  Shift: Integer;
begin
  Shift := (Grid.TopRow - FPrevTopRow) *
    (Grid.DefaultRowHeight + Grid.GridLineWidth);
  for I := 0 to Grid.ControlCount - 1 do
  begin
    Grid.Controls[I].Top := Grid.Controls[I].Top - Shift;
    Grid.Controls[I].Visible := Grid.Controls[I].Top > 0;
  end;
end;

function TForm1.GetInsertRowCount(ARow: Integer): Integer;
begin
  //This function should return the number of rows which is to be inserted
  //below ARow. Note that ARow refers to the original row index, that is:
  //without account for already inserted rows. For now, assume three rows:
  Result := 3;
end;

function TForm1.GridButtonToRow(AButton: TButton): Integer;
begin
  for Result := 0 to Grid.RowCount - 1 do
    if Grid.Objects[0, Result] = AButton then
      Exit;
  Result := -1;
end;

procedure TForm1.MoveGridButtons(ButtonIndex, ARowCount: Integer);
var
  I: Integer;
begin
  for I := 0 to Grid.ControlCount - 1 do
    if Grid.Controls[I].Tag > ButtonIndex then
      Grid.Controls[I].Top := Grid.Controls[I].Top +
        ARowCount * (Grid.DefaultRowHeight + Grid.GridLineWidth);
end;

end.

しかし、これはボタン コントロールを使用しなくても可能であると言えます。文字列グリッドの OnDrawCell イベントで偽のボタン コントロールを描画することをお勧めします。

于 2012-01-29T09:32:28.137 に答える