Струнная сетка с кнопками - PullRequest
2 голосов
/ 28 января 2012

1-й вопрос:

Как вы называете часть в сетке строк, которая не видна? Вам нужно прокрутить, чтобы увидеть это.
Например:
В сетке 20 строк, но вы можете видеть только 10 строк одновременно. Вам нужно прокрутить, чтобы увидеть другие 10. Как называются «скрытые»?

2-й вопрос:

Я знаю, что это, вероятно, неправильный способ сделать это, поэтому некоторые указатели будут оценены.
У меня есть сетка строк с 1 фиксированной строкой. Я добавляю ColorButtons во время выполнения. Поэтому я заполняю 1 столбец кнопками. Я использую эти кнопки для «вставки / удаления» строк. Пока вся сетка находится в «видимой» части, это работает хорошо. Проблема возникает, когда я «вставляю» новые строки и перемещаю кнопки в «скрытую» часть. Последняя кнопка затем обращается к ячейке [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;

1 Ответ

5 голосов
/ 29 января 2012
  1. Для видимой части существуют свойства VisibleRowCount и VisibleColCount.Тип записи TGridAxisDrawInfo дает имена видимой части Граница и всем частям вместе Степень (или наоборот, я никогда не помню).Таким образом, для невидимой части строковой сетки нет конкретного объявленного VCL имени.Это просто невидимая часть .

  2. Я думаю, вы делаете логическую ошибку: кнопки не перемещаются при прокрутке сетки,Хотя может показаться, что они перемещаются, это всего лишь результат перемещения содержимого контекста устройства из-за внутреннего вызова ScrollWindow.Полосы прокрутки в компоненте сетки строк добавляются пользователем и работают не так, как, например, TScrollBox.

    Чтобы всегда отображать все кнопки в тех местах, где они действительно находятся, перекрасьте сетку строк вOnTopLeftChanged событие:

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

    Если высота строк всех строк и высота сетки строк никогда не изменяются, то достаточно создать все кнопки только один раз и оставить их на месте.Это означает, что каждая кнопка больше не «привязана» к строке, и сохранение их в свойстве 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 сетки.

...