Getting the cell clicked on in a TGridPanel
-
26-10-2019 - |
Pergunta
I have a TGridPanel
on a form and wish to add a control to a specific "cell" that is clicked on.
I can get the point easily enough:
procedure TForm1.GridPanel1DblClick(Sender: TObject);
var
P : TPoint;
InsCol, InsRow : Integer;
begin
P := (Sender as TGridPanel).ScreenToClient(Mouse.CursorPos);
if (Sender as TGridPanel).ControlAtPos(P) = nil then
begin
InsCol := ???;
InsRow := ???;
(Sender as TGridPanel).ControlCollection.AddControl(MyControl, InsCol, InsRow)
end;
end;
I probably don't need the if ControlAtPos(P) = nil then
line, but I want to make sure I'm not inserting a control in a cell that already has one in it.
So... what code do I use to get InsCol and InsRow? I've been up and down the TGridPanel
and TControlCollection
class code and can't find anything that will give me a column or row value from mouse coordinates. Nor does their seem to be a relevant event to use other than OnDblClick()
.
Any help would be greatly appreciated.
EDIT: Changed variable Result to MyControl to avoid confusion.
Solução
procedure TForm1.GridPanel1Click(Sender: TObject);
var
P: TPoint;
R: TRect;
InsCol, InsRow : Integer;
begin
P := (Sender as TGridPanel).ScreenToClient(Mouse.CursorPos);
for InsCol := 0 to GridPanel1.ColumnCollection.Count - 1 do
begin
for InsRow := 0 to GridPanel1.RowCollection.Count - 1 do
begin
R:= GridPanel1.CellRect[InsCol,InsRow];
if PointInRect(P,R) then
begin
ShowMessage (Format('InsCol = %s and InsRow = %s.',[IntToStr(InsCol), IntToStr(InsRow)]))
end;
end;
end;
end;
function TForm1.PointInRect(aPoint: TPoint; aRect: TRect): boolean;
begin
begin
Result:=(aPoint.X >= aRect.Left ) and
(aPoint.X < aRect.Right ) and
(aPoint.Y >= aRect.Top ) and
(aPoint.Y < aRect.Bottom);
end;
end;
Outras dicas
Here is an optimization of Ravaut123's approach (should be MUCH faster for larger grids). This function will return the X/Y grid location in a TPoint. If the user clicked on a valid column but not a valid row, then the valid column information is still returned, and the same goes for rows. So it isn't "all or nothing" (valid cell or invalid cell). This function assumes the grid is "regular" (every column has the same row height as the first column, likewise every row has the same column width as the first row). If the grid is not regular then Ravaut123's solution is the better choice.
// APoint is a point in local coordinates for which you want to find the cell location.
function FindCellInGridPanel(AGridPanel: TGridPanel; const APoint: TPoint): TPoint;
var
ICol, IRow : Integer;
R : TRect;
begin
Result.X := -1;
Result.Y := -1;
for ICol := 0 to AGridPanel.ColumnCollection.Count - 1 do
begin
R := AGridPanel.CellRect[ICol, 0];
if (APoint.X >= R.Left) and (APoint.X <= R.Right) then
begin
Result.X := ICol;
Break;
end;
end;
for IRow := 0 to AGridPanel.RowCollection.Count - 1 do
begin
R := AGridPanel.CellRect[0, IRow];
if (APoint.Y >= R.Top) and (APoint.Y <= R.Bottom) then
begin
Result.Y := IRow;
Break;
end;
end;
end;