Mega Code Archive

 
Categories / Delphi / VCL
 

Replacing the TStringGrids standard InplaceEditor

Title: Replacing the TStringGrid's standard InplaceEditor Question: How can I modify a TStringGrid to have a picklist or an ellipsis editor button in selected cells? Answer: Replacing the TStringGrid's standard InplaceEditor The TStringGrid is a widely used Delphi component. It is possible to enter text directly into the grid cells, but it is sometimes desirable to use alternative inplace editors, such as a combobox to select from a picklist of values, or a user dialog called by clicking on an ellipsis button in the corresponding grid cell. While this is a standard behavior for a TDBGrid, it is not available for the non-data aware TStringGrid. Some solutions can be found all over the web, but the basic functionality, however, has been implemented already in the ancestor of any grid, TCustomGrid. I'm working with Delphi 6, but I think this schould be true also for older versions. The corresponding inplace editor which has all the features mentioned can be found in the Grids unit as TInplaceEditList. It can be accessed by inheriting from TStringGrid a new component which will be named TNewStringGrid here. In this new component, the method "CreateEditor" is overridden to use the TInplaceEditList as inplace editor (instead of the standard TInplaceEdit). The new stringgrid also inherits the method "GetEditStyle" which decides which cells will use the new inplace editor. In the implementation of TNewStringGrid, we create a new event "OnGetEditStyle" which calls the GetEditStyle method. The event handler receives the cell coordinates and returns the editor style (esSimple, esPickList or esEllipsis, as defined in grids.pas). Additionally for the esPicklist editor style, we have to write an event handler for the "OnGetPickListItems" event to pass the pick list (a TStringList) to the new string grid. For the esEllipsis editor style, we need an event handler for the event "OnEditButtonClicked" which is fired when the user clicks on the new ellipsis button; this event handler for example could open a complex dialog querying user input and should fill the cell with the corresponding text entered. Don't forget to activate the goEditing option of the stringgrid; otherwise you won't be able to edit the grid data. ------------------------------------------------------------------------------- What follows is the source of TNewStringGrid unit: unit NewStringGrid; interface uses Windows, Messages, SysUtils, Classes, Controls, Grids; type TGetEditStyleEvent = procedure (TSender:TObject; ACol,ARow:integer; var EditStyle:TEditStyle) of object; TNewStringGrid = class(TStringGrid) private FDropdownRowCount : integer; FOnEditButtonClick : TNotifyEvent; FOnGetEditStyle : TGetEditStyleEvent; FOnGetPickListItems : TOnGetPickListItems; procedure SetDropdownRowCount(value:integer); procedure SetOnEditButtonClick(value:TNotifyEvent); procedure SetOnGetPicklistItems(value:TOnGetPickListItems); protected function CreateEditor: TInplaceEdit; override; function GetEditStyle(ACol, ARow: integer): TEditStyle; override; public constructor Create(AOwner:TComponent); override; published property DropdownRowCount : integer read FDropDownRowCount write SetDropdownRowCount default 8; property OnEditButtonClick: TNotifyEvent read FOnEditButtonClick write SetOnEditButtonClick; property OnGetEditStyle : TGetEditStyleEvent read FOnGetEditStyle write FOnGetEditStyle; property OnGetPickListItems : TOnGetPickListItems read FOnGetPickListItems write SetOnGetPickListItems; end; procedure Register; implementation constructor TNewStringGrid.Create(AOwner:TComponent); begin inherited Create(AOwner); FDropdownRowCount := 8; end; function TNewStringGrid.CreateEditor: TInplaceEdit; begin result := TInplaceEditList.Create(self); with TInplaceEditList(result) do begin DropdownRows := FDropdownRowCount; OnGetPickListItems := FOnGetPickListItems; OnEditButtonClick := FOnEditButtonClick; end; end; function TNewStringGrid.GetEditStyle(ACol,ARow:integer) : TEditStyle; begin result := esSimple; if Assigned(FOnGetEditStyle) then FOnGetEditStyle(self, ACol, ARow, result); end; procedure TNewStringGrid.SetDropDownRowCount(value:integer); begin FDropdownRowCount := value; if Assigned(InplaceEditor) then TInplaceEditList(InplaceEditor).DropdownRows := value; end; procedure TNewStringGrid.SetOnEditButtonClick(value:TNotifyEvent); begin FOnEditButtonClick := value; if Assigned(InplaceEditor) then TInplaceEditList(InplaceEditor).OnEditButtonClick := value; end; procedure TNewStringGrid.SetOnGetPicklistItems(value:TOnGetPicklistItems); begin FOnGetPicklistItems := value; if Assigned(InplaceEditor) then TInplaceEditList(InplaceEditor).OnGetPickListitems := value; end; procedure Register; begin RegisterComponents('Additional', [TNewStringGrid]); end; end. ------------------------------------------------------------------------------- Here is a little demo project: unit TestUnit; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Grids, NewStringGrid; type TForm1 = class(TForm) NewStringGrid1: TNewStringGrid; procedure FormCreate(Sender: TObject); procedure NewStringGrid1GetEditStyle(TSender: TObject; ACol, ARow: Integer; var EditStyle: TEditStyle); procedure NewStringGrid1GetPickListItems(ACol, ARow: Integer; Items: TStrings); procedure NewStringGrid1EditButtonClick(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private-Deklarationen } PickList : TStringList; public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); var i,r,c : integer; const n = 10; begin with NewStringGrid1 do begin for r:=1 to RowCount-1 do Cells[0,r] := IntToStr(r); for c:=1 to ColCount-1 do Cells[c,0] := char(ord('A')+c-1); end; PickList := TStringList.Create; for i:=1 to n do PickList.Add(Format('Item %d', [i])); end; procedure TForm1.FormDestroy(Sender: TObject); begin PickList.Free; end; procedure TForm1.NewStringGrid1GetEditStyle(TSender: TObject; ACol,ARow: Integer; var EditStyle: TEditStyle); begin if ACol=1 then EditStyle := esPickList; if ACol=2 then EditStyle := esEllipsis; end; procedure TForm1.NewStringGrid1GetPickListItems(ACol, ARow: Integer; Items: TStrings); begin Items.Assign(PickList); end; procedure TForm1.NewStringGrid1EditButtonClick(Sender: TObject); var s : string; begin with NewStringGrid1 do Cells[Col,Row] := Inputbox('Enter your data', 'Data:', Cells[Col,Row]); end; end. ----------------------------------------------- object Form1: TForm1 Left = 200 Top = 107 Width = 416 Height = 303 Caption = 'Test Form' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate OnDestroy = FormDestroy PixelsPerInch = 96 TextHeight = 13 object NewStringGrid1: TNewStringGrid Left = 0 Top = 0 Width = 408 Height = 276 Align = alClient ColCount = 10 Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goEditing, goAlwaysShowEditor] TabOrder = 0 OnEditButtonClick = NewStringGrid1EditButtonClick OnGetEditStyle = NewStringGrid1GetEditStyle OnGetPickListItems = NewStringGrid1GetPickListItems end end