mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-03 18:06:34 +02:00

Examples: Fix uninitialized variable issue in gridexamples/merged_cells (https://forum.lazarus.freepascal.org/index.php/topic,41757.msg290284) ........ git-svn-id: branches/fixes_1_8@58726 -
210 lines
6.2 KiB
ObjectPascal
210 lines
6.2 KiB
ObjectPascal
unit mcgrid;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Grids;
|
|
|
|
type
|
|
TDrawCellTextEvent = procedure (Sender: TObject; ACol, ARow: Integer;
|
|
ARect: TRect; AState: TGridDrawState; AText: String;
|
|
var Handled: Boolean) of object;
|
|
|
|
TMergeCellsEvent = procedure (Sender: TObject; ACol, ARow: Integer;
|
|
var ALeft, ATop, ARight, ABottom: Integer) of object;
|
|
|
|
{ TMCStringGrid: MC = "merged cells" }
|
|
|
|
TMCStringGrid = class(TStringGrid)
|
|
private
|
|
FMergeLock: Integer;
|
|
FOnMergeCells: TMergeCellsEvent;
|
|
FOnDrawCellText: TDrawCellTextEvent;
|
|
protected
|
|
procedure CalcCellExtent(ACol, ARow: Integer; var ARect: TRect); override;
|
|
procedure DoEditorShow; override;
|
|
procedure DrawAllRows; override;
|
|
procedure DrawCellText(ACol, ARow: Integer; ARect: TRect;
|
|
AState: TGridDrawState; AText: String); override;
|
|
procedure DrawFocusRect(ACol, ARow:Integer; ARect:TRect); override;
|
|
function GetCells(ACol, ARow: Integer): String; override;
|
|
function GetEditText(ACol, ARow: Integer): String; override;
|
|
function IsMerged(ACol, ARow: Integer): Boolean; overload;
|
|
function IsMerged(ACol, ARow: Integer;
|
|
out ALeft, ATop, ARight, ABottom: Integer): Boolean; overload;
|
|
procedure MoveSelection; override;
|
|
procedure PrepareCanvas(aCol, aRow: Integer; AState: TGridDrawState); override;
|
|
procedure SetEditText(ACol, ARow: LongInt; const Value: String); override;
|
|
published
|
|
property OnDrawCelLText: TDrawCellTextEvent read FOnDrawCellText write FOnDrawCellText;
|
|
property OnMergeCells: TMergeCellsEvent read FOnMergeCells write FOnMergeCells;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
{ Calculates the size of the merged block }
|
|
procedure TMCStringGrid.CalcCellExtent(ACol, ARow: Integer; var ARect: TRect);
|
|
var
|
|
L, T, R, B: Integer;
|
|
begin
|
|
if IsMerged(ACol, ARow, L, T, R, B) then begin
|
|
ARect.TopLeft := CellRect(L, T).TopLeft;
|
|
ARect.BottomRight := CellRect(R, B).BottomRight;
|
|
end;
|
|
|
|
// Call the inherited procedure to handle non-merged cells
|
|
inherited;
|
|
end;
|
|
|
|
{ Make sure that the cell editor of a merged block is the same size as the
|
|
merged block }
|
|
procedure TMCStringGrid.DoEditorShow;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
inherited;
|
|
if (goColSpanning in Options) and Assigned(Editor) then begin
|
|
R := CellRect(Col, Row);
|
|
CalcCellExtent(Col, Row, R);
|
|
Editor.SetBounds(R.Left, R.Top, R.Right-R.Left-1, R.Bottom-R.Top-1);
|
|
end;
|
|
end;
|
|
|
|
{ Redraws the FocusRect after all cells have been painted. Otherwise the
|
|
FocusRect might not be complete }
|
|
procedure TMCStringGrid.DrawAllRows;
|
|
var
|
|
L, T, R, B: Integer;
|
|
rct: TRect;
|
|
begin
|
|
inherited;
|
|
if FocusRectVisible and IsMerged(Col, Row, L, T, R, B) then begin
|
|
rct.TopLeft := CellRect(L, T).TopLeft;
|
|
rct.BottomRight := CellRect(R, B).BottomRight;
|
|
DrawFocusRect(L, T, rct);
|
|
end;
|
|
end;
|
|
|
|
{ Draws the cell text. Allows to hook in an external painting routine which
|
|
will replace the built-in painting routine if it sets "Handled" to true. }
|
|
procedure TMCStringGrid.DrawCellText(ACol, ARow: Integer; ARect: TRect;
|
|
AState: TGridDrawState; AText: String);
|
|
var
|
|
handled: Boolean;
|
|
begin
|
|
handled := false;
|
|
if Assigned(FOnDrawCellText) then
|
|
FOnDrawCellText(Self, ACol, ARow, ARect, AState, AText, handled);
|
|
if not handled then
|
|
inherited;
|
|
end;
|
|
|
|
{ makes sure that the focus rect is drawn to enclose all cells of a
|
|
merged block }
|
|
procedure TMCStringGrid.DrawFocusRect(ACol, ARow: Integer; ARect: TRect);
|
|
begin
|
|
CalcCellExtent(ACol, ARow, ARect);
|
|
inherited DrawFocusRect(ACol, ARow, ARect);
|
|
end;
|
|
|
|
{ Returns the string to be displayed in the specified cell. In case of a merged
|
|
block only the text assigned to the top-left cell of the block is used. }
|
|
function TMCStringGrid.GetCells(ACol, ARow: Integer): String;
|
|
var
|
|
L, T, R, B: Integer;
|
|
begin
|
|
if (FMergeLock = 0) and IsMerged(ACol, ARow, L, T, R, B) then
|
|
Result := inherited GetCells(L, T)
|
|
else
|
|
Result := inherited GetCells(ACol, ARow);
|
|
end;
|
|
|
|
{ Make sure to use only the topleft cell of a merged block for editing }
|
|
function TMCStringGrid.GetEditText(ACol, ARow: Integer): String;
|
|
begin
|
|
Result := GetCells(ACol, ARow);
|
|
if Assigned(OnGetEditText) then OnGetEditText(self, ACol, ARow, Result);
|
|
end;
|
|
|
|
{ Check whether the specified cell belongs to a merged block}
|
|
function TMCStringGrid.IsMerged(ACol, ARow: Integer): Boolean;
|
|
var
|
|
L, T, R, B: Integer;
|
|
begin
|
|
Result := IsMerged(ACol, ARow, L, T, R, B);
|
|
end;
|
|
|
|
{ Checks whether the specified cell belongs to a merged block and returns the
|
|
cell coordinate of the block extent }
|
|
function TMCStringGrid.IsMerged(ACol,ARow: Integer;
|
|
out ALeft, ATop, ARight, ABottom: Integer): Boolean;
|
|
var
|
|
tmp: Integer;
|
|
begin
|
|
Result := false;
|
|
if not (goColSpanning in Options) then exit;
|
|
if not Assigned(FOnMergeCells) then exit;
|
|
inc(FMergeLock);
|
|
|
|
ALeft := ACol;
|
|
ARight := ACol;
|
|
ATop := ARow;
|
|
ABottom := ARow;
|
|
FOnMergeCells(Self, ACol, ARow, ALeft, ATop, ARight, ABottom);
|
|
if ALeft > ARight then begin
|
|
tmp := ALeft;
|
|
ALeft := ARight;
|
|
ARight := tmp;
|
|
end;
|
|
if ATop > ABottom then begin
|
|
tmp := ATop;
|
|
ATop := ABottom;
|
|
ABottom := tmp;
|
|
end;
|
|
Result := (ALeft <> ARight) or (ATop <> ABottom);
|
|
dec(FMergeLock);
|
|
end;
|
|
|
|
{ Repaints the entire grid after the selection is moved because normally only
|
|
the selected cell would be painted, and this would result in an imcompletely
|
|
painted merged block }
|
|
procedure TMCStringGrid.MoveSelection;
|
|
begin
|
|
inherited;
|
|
InvalidateGrid;
|
|
end;
|
|
|
|
{ Makes sure that all cells of the merged block are drawn as selected/focused,
|
|
not just the active cell }
|
|
procedure TMCStringGrid.PrepareCanvas(aCol, aRow: Integer;
|
|
AState: TGridDrawState);
|
|
var
|
|
L, T, R, B: Integer;
|
|
begin
|
|
if IsMerged(ACol, ARow, L, T, R, B) and
|
|
(Col >= L) and (Col <= R) and (Row >= T) and (Row <= B) and
|
|
not ((ACol = Col) and (ARow = Row))
|
|
then
|
|
AState := AState + [gdSelected, gdFocused];
|
|
inherited;
|
|
end;
|
|
|
|
{ Writes the edited text back into the grid. Makes sure that, in case of a
|
|
merged block, the edited text is assigned to the top/left cell }
|
|
procedure TMCStringGrid.SetEditText(ACol, ARow: LongInt; const Value: String);
|
|
var
|
|
L, T, R, B: Integer;
|
|
begin
|
|
if IsMerged(ACol, ARow, L,T,R,B) then
|
|
inherited SetEditText(L, T, Value)
|
|
else
|
|
inherited SetEditText(ACol, ARow, Value);
|
|
end;
|
|
|
|
|
|
end.
|
|
|