Home > Enterprise >  Change the order of rows in TGridPanel by button click
Change the order of rows in TGridPanel by button click

Time:10-22

I like to change the order of rows in a TGridPanel by clicking a button. The Gridpanel rows are dymamically created and contain a Panel with a manually docked form. The form has its own edit components and a Label with the index of the current row. The best way would be like this:

  1. Mark the row by clicking it
  2. Click a button "up" or "down".
  3. The selected row moves up/down.
  4. The Index of the row changes in the docked form.

Here is my attempt:

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    GridPanel1->RowCollection->Clear();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::BitBtn_StepAddClick(TObject *Sender)
{
    GridPanel1->RowCollection->BeginUpdate();

    if (GridPanel1->RowCollection->Count > 0)
        GridPanel1->Height = GridPanel1->Height   156;

    TRowItem * RowItem = GridPanel1->RowCollection->Add();
    RowItem->SizeStyle = ssAbsolute;
    RowItem->Value     = 156;

    TPanel * Panel2 = new TPanel(this);
    Panel2->Parent = GridPanel1;
    Panel2->Color  = clWhite;
    Panel2->Name   = "Panel"   IntToStr(GridPanel1->RowCollection->Count)   "2";
    Panel2->Align  = alClient;
    Panel2->AlignWithMargins = false;

    TForm2 * Form2 = new TForm2(this, GridPanel1->RowCollection->Count);
    Form2->ManualDock(Panel2, Panel2, alClient);
    Form2->Show();

    BitBtn_StepDelete->Enabled = true;

    GridPanel1->RowCollection->EndUpdate();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::BitBtn_StepDeleteClick(TObject *Sender)
{
    // at the moment this button deletes the last row in GridPanel. But it would be fine to select a row by clicking it and delete the selected one.
    // After deleting it, the titles of the manually docked forms should change
    GridPanel1->RowCollection->BeginUpdate();

    GridPanel1->ControlCollection->Delete(GridPanel1->ControlCollection->Count - 1);
    GridPanel1->RowCollection->Delete(GridPanel1->RowCollection->Count - 1);

    if (GridPanel1->RowCollection->Count > 0)
        GridPanel1->Height = GridPanel1->Height - 156;
    else
        BitBtn_StepDelete->Enabled = false;

    GridPanel1->RowCollection->EndUpdate();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::BitBtn_StepInsertClick(TObject *Sender)
{
    // Select a row by clicking it and then add a new row before
}
//---------------------------------------------------------------------------

void __fastcall TForm1::BitBtn_StepUpClick(TObject *Sender)
{
    // Select a row by clicking it and move it up by this button click
}
//---------------------------------------------------------------------------

void __fastcall TForm1::BitBtn_StepDownClick(TObject *Sender)
{
    // Select a row by clicking it and move it down by this button click
}
//---------------------------------------------------------------------------

Does anyone have an idea?

CodePudding user response:

Here's a Delphi implementation of a MoveUp button click handler. It depends on a variable SelRowId: integer holding the currently selected row index, or -1 if none selected.

It doesn't move the rows, but rather the content (e.g. panel) from one cell to another.

procedure TForm39.MoveUpBtnClick(Sender: TObject);
var
  NewRowId: integer;
begin
  GridPanel1.RowCollection.BeginUpdate;

  if InRange(SelRowId, 1, GridPanel1.ControlCollection.Count-1) then
  begin
    NewRowId := SelRowId - 1;
    GridPanel1.ControlCollection.ControlItems[0,SelRowId].Row := NewRowId;
    SelRowId := NewRowId;
  end;

  GridPanel1.RowCollection.EndUpdate;
end;

The MoveDown procedure is otherwise similar, but the test of SelRowId is

if InRange(SelRowId, 0, GridPanel1.ControlCollection.Count-2)

and assignment of NewRowId is

`NewRowId := SelRowId   1;`

SelRowId must be initialized to -1, and set to -1 whenever no panels are selected.

I have assumed in my test app that clicking a panel ...

// Clicking a panel
// - deselects the panel if it was previously selected
// - deselects any other previously selected panel in preparation to:
// - selects the panel if it was not previously selected

In my test application I get the selected panels row in two steps:

  1. Get the index of the panel via ControlCollection.IndexOf(panel)

  2. Get the row from ControlCollection[indx]

    var
      indx: integer;
      Panel: TPanel;

    Panel := Sender as TPanel;
    {...}
    indx := TGridPanel(Panel.Parent).ControlCollection.IndexOf(Panel);
    SelRowId := TGridPanel(Panel.Parent).ControlCollection[indx].Row;

The complete implementation of my test project is here:

implementation

{$R *.dfm}
uses Math;

procedure TForm39.FormCreate(Sender: TObject);
begin
  SelRowId := -1;
end;

procedure TForm39.MoveUpBtnClick(Sender: TObject);
var
  NewRowId: integer;
begin
  GridPanel1.RowCollection.BeginUpdate;

  if InRange(SelRowId, 1, GridPanel1.ControlCollection.Count-1) then
  begin
    NewRowId := SelRowId - 1;
    GridPanel1.ControlCollection.ControlItems[0,SelRowId].Row := NewRowId;
    SelRowId := NewRowId;
  end;

  GridPanel1.RowCollection.EndUpdate;
end;

procedure TForm39.MoveDnBtnClick(Sender: TObject);
var
  NewRowId: integer;
begin
  GridPanel1.RowCollection.BeginUpdate;

  if InRange(SelRowId, 0, GridPanel1.ControlCollection.Count-2) then
  begin
    NewRowId := SelRowId   1;
    GridPanel1.ControlCollection.ControlItems[0,SelRowId].Row := NewRowId;
    SelRowId := NewRowId;
  end;

  GridPanel1.RowCollection.EndUpdate;
end;

procedure TForm39.AddStepBtnClick(Sender: TObject);
var
  NewRow: TRowItem;
  P: Tpanel;
begin
  GridPanel1.RowCollection.BeginUpdate;

  NewRow := GridPanel1.RowCollection.Add;
  GridPanel1.Height := GridPanel1.Height   50;
  NewRow.SizeStyle := ssAbsolute;
  NewRow.Value := 50;

  P := Tpanel.Create(self);
  P.Caption := 'Panel ' IntToStr(GridPanel1.RowCollection.Count);
  P.Align := alClient;
  P.AlignWithMargins := False;
  P.Parent := GridPanel1;
  P.ParentBackground := False;
  P.ParentColor := False;
  P.Color := Random(256) shl 16   Random(256) shl 8   Random(256);
  P.OnClick := PanelClick;

  GridPanel1.RowCollection.EndUpdate;
end;

// Clicking a panel
// - selects the panel if it was not previously selected
// - deselects the panel if it was previously selected
// - deselects any other previously selected panel
procedure TForm39.PanelClick(Sender: TObject);
var
  indx: integer;
  Panel: TPanel;
begin
  Panel := Sender as TPanel;

  // previously selected panel
  if Assigned(SelPanel) then
    SelPanel.Color := SavedColor; // reset its color
  if SelPanel = Panel then        // a second click unselects
  begin
    SelPanel := nil;
    SelRowId := -1;
    Exit;
  end;

  SavedColor := Panel.Color;  // save newly selected panels color
  Panel.Color := clRed;       // set selected color
  SelPanel := Panel;          // set selected panel

  indx := TGridPanel(Panel.Parent).ControlCollection.IndexOf(Panel);
  SelRowId := TGridPanel(Panel.Parent).ControlCollection[indx].Row;
end;
  • Related