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:
- Mark the row by clicking it
- Click a button "up" or "down".
- The selected row moves up/down.
- 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:
Get the index of the panel via
ControlCollection.IndexOf(panel)
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;