I use a completely different way to complete the task ... Create an integer unit to add the method to ExtCtrls.TControlCollection without touching the ExtCtrls unit (first hack), and use this method InternalSetLocation (second hack). I also explain both hacks in this post.
Then I just need to add such a block to the usage usage section (before the gridpanel declaration) and call the method I created ... very easy to use.
Here is how I do it, step by step:
- I include a block that I masked for such a job in the project (add file)
- I add TForm to my interface using a section such a block (or where I need it)
- I use my
AddControlAtCell method instead of ExtCtrls.TControlCollection.AddControl
Here is the block I created for such a job, save it as unitTGridPanel_WithAddControlAtCell :
unit unitTGridPanel_WithAddControlAtCell; interface uses Controls ,ExtCtrls ; type TGridPanel=class(ExtCtrls.TGridPanel) private public procedure AddControlAtCell(AControl:TControl;AColumn:Integer;ARow:Integer); // Add Control on specifed cell, if there already exists a Control it will be deleted end; implementation uses SysUtils ; type THackControlItem=class(TControlItem); // To get internal access to InternalSetLocation procedure procedure TGridPanel.AddControlAtCell(AControl:TControl;AColumn:Integer;ARow:Integer); var TheControlItem:TControlItem; // To let it be added in a specified cell, since ExtCtrls.TControlCollection.AddControl contains multiply BUGs begin // Add Control on specifed cell, if there already exists a Control it will be deleted if (-1<AColumn)and(AColumn<ColumnCollection.Count) // Cell with valid Column and // Cell inside valid range (-1<ARow)and(ARow<RowCollection.Count) // Cell with valid Row then begin // Valid cell, must check if there is already a control if (Nil<>ControlCollection.ControlItems[AColumn,ARow]) // Check if there are any controls and // A control is already on the cell (Nil<>ControlCollection.ControlItems[AColumn,ARow].Control) // Check if cell has a control then begin // There is already a control, must be deleted ControlCollection.Delete(ControlCollection.IndexOf(ControlCollection.ControlItems[AColumn,ARow].Control)); // Delete the control end; TheControlItem:=ControlCollection.Add; // Create the TControlItem TheControlItem.Control:=TControl(AControl); // Put the Control in the specified cell without altering any other cell THackControlItem(ControlCollection.Items[ControlCollection.IndexOf(AControl)]).InternalSetLocation(AColumn,ARow,False,False); // Put the ControlItem in the cell without altering any other cell end else begin // Cell is out of range raise Exception.CreateFmt('Cell [%d,%d] out of range on ''%s''.',[AColumn,ARow,Name]); end; end; end.
I hope the comments are clear enough, please read them to understand why and how I do it.
Then, when I need to add a control to the grid in the specified cell, I make the following simple call:
TheGridPanel.AddControlAtCell(TheControl,ACloumn,ARow);
A very simple example of adding a newly created TCheckBox in a specific cell might be:
// AColumn is of Type Integer // ARow is of Type Integer // ACheckBox is of Type TCheckBox // TheGridPanel is of Type TGridPanel ACheckBox:=TCheckBox.Create(TheGridPanel); // Create the Control to be added (a CheckBox) ACheckBox.Visible:=False; // Set it to not visible, for now (optimization on speed, e tc) ACheckBox.Color:=TheGridPanel.Color; // Just to use same background as on the gridpanel ACheckBox.Parent:=TheGridPanel; // Set the parent of the control as the gridpanel (mandatory) TheGridPanel.AddControlAtCell(ElCheckBox,ACloumn,ARow); // Add it at desired cell without affecting other cells ElCheckBox.Visible:=True; // Now it is added, make it visible ElCheckBox.Enabled:=True; // And of course, ensure it is enabled if needed
Note that I use these two hacks:
type THackControlItem Let me access the InternalSetLocation method.type TGridPanel=class(ExtCtrls.TGridPanel) Let me add the ExtCtrls.TGridPanel method ExtCtrls.TGridPanel even touching (without needing an ExtCtrls source)
Important. Also note that I mention that it requires adding a module to the use of the interface of each form, where you want to use the AddControlAtCell method; that is, for normal people, advanced people can also create another unit, etc. The "concept" is for the unit to use before the GridPanel declaration where you use it ... example: if the GridPanel is exposed on the form during development ... it must continue to use such a form unit.
Hope this helps someone else.