In Lazarus (and any others RAD), a TStringGrid
visual component is a key component for input/output data from DataSet
or self-contained. This data is stored in cells as string data type.
I'm wondering if there is any custom grid component that supports float or integer number manipulation and associated methods.
For example:
A grid component which captures input from the user in cells (as usual) and if the data captured is a String
, internally and automatically convert this data input in corresponding numeric value as Single
or Integer
data type for indeed manipulation and display data as usual.
Additionally, if the numeric value for the cell is modified, then also change string representation.
I think a component like this is very useful in case of we need a grid that stored numeric values only (without including a header row, maybe).
Can any of you know if exist a component like that or provide examples or source code about this component?
Thanks a lot and best regards
The answer depends on what you mean with "float or integer number manipulation".
If you want to execute calculations within the grid, like in a spreadsheet, you should try the fpspreadsheet package (https://sourceforge.net/projects/lazarus-ccr/files/FPSpreadsheet/fpspreadsheet-1.6.2.zip/download, or https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/fpspreadsheet/). It contains a dedicated grid in which you can enter formulas like in Excel. Each cell stores data essentially as string or number,depending on the data type. See http://wiki.lazarus.freepascal.org/TsWorksheetGrid for an introduction.
If, on the other hand, you have a "matrix" of numbers (2D-array) and want to display them in a grid without storing the converted strings permanently like in a StringGrid, you should have a look at the standard TDrawGrid which comes with Lazarus (and Delphi). This grid provides everything that the TStringGrid has except for the strings themselves. Data are converted to strings "on the fly" whenever they are needed and then discarded again. In order to display and edit the numbers you must implement these event handlers:
OnDrawCell
: converts the number to be displayed in a particular cell to a string, and paints the string to the canvas of the gridOnGetEditText
, again, converts the number to a string, but now for editing since this string will be passed to the cell editor.OnSetEditText
gets the string from the cell editor and must convert it to a number which must be inserted into the data matrix.Here is the basic code for the DrawGrid approach. Just add a TDrawGrid to a form and assign the mentioned event handlers. FData
is a dummy matrix of random numbers which is created by the CreateData
method.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Grids;
type
{ TForm1 }
TMatrix = array of array of double;
TForm1 = class(TForm)
DrawGrid1: TDrawGrid;
procedure DrawGrid1DrawCell(Sender: TObject; aCol, aRow: Integer;
aRect: TRect; aState: TGridDrawState);
procedure DrawGrid1GetEditText(Sender: TObject; ACol, ARow: Integer;
var Value: string);
procedure DrawGrid1SetEditText(Sender: TObject; ACol, ARow: Integer;
const Value: string);
procedure FormCreate(Sender: TObject);
private
FData: TMatrix;
procedure CreateData;
procedure PrepareGrid;
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
CreateData;
PrepareGrid;
end;
procedure TForm1.CreateData;
var
r, c: Integer;
begin
SetLength(FData, 5, 10); // 1st index = col = x, 2nd index = row = y
for r := 0 to High(FData[0]) do
for c := 0 to High(FData) do
FData[c, r] := random*100;
end;
procedure TForm1.DrawGrid1DrawCell(Sender: TObject; aCol, aRow: Integer;
aRect: TRect; aState: TGridDrawState);
var
s: String;
xpos, ypos: Integer;
begin
if (aRow = 0) and (aCol = 0) and
(DrawGrid1.fixedRows > 0) and (DrawGrid1.Fixedcols > 0) then
exit;
// Fixed row
if (aRow = 0) and (DrawGrid1.FixedRows > 0) then begin
s := Format('Col %d', [aCol - DrawGrid1.FixedCols]);
xpos := (aRect.Left + aRect.Right - DrawGrid1.Canvas.TextWidth(s)) div 2;
end else
// Fixed col
if (aCol = 0) and (DrawGrid1.FixedCols > 0) then begin
s := Format('Row %d', [aRow - DrawGrid1.FixedRows]);
xpos := (aRect.Left + aRect.Right - DrawGrid1.Canvas.TextWidth(s)) div 2;
end else begin
// Normal cells
s := FormatFloat('0.000', FData[aCol-DrawGrid1.FixedCols, aRow-DrawGrid1.FixedRows]);
xpos := aRect.Right - constCellPadding - DrawGrid1.Canvas.TextWidth(s);
end;
ypos := (aRect.Top + aRect.Bottom - DrawGrid1.Canvas.TextHeight('Tg')) div 2;
// Draw cell text
DrawGrid1.Canvas.TextOut(xpos, ypos, s);
end;
procedure TForm1.DrawGrid1GetEditText(Sender: TObject; ACol, ARow: Integer;
var Value: string);
begin
Value := FormatFloat('0.000', FData[ACol - DrawGrid1.FixedCols, ARow - DrawGrid1.FixedRows]);
end;
procedure TForm1.DrawGrid1SetEditText(Sender: TObject; ACol, ARow: Integer;
const Value: string);
var
number: Double;
begin
if TryStrToFloat(Value, number) then
FData[ACol - DrawGrid1.FixedCols, ARow - DrawGrid1.FixedRows] := number;
end;
procedure TForm1.PrepareGrid;
begin
DrawGrid1.RowCount := Length(FData[0]) + DrawGrid1.FixedRows;
DrawGrid1.ColCount := Length(FData) + DrawGrid1.FixedCols;
Invalidate;
end;
end.