StringGrid - substituir o editor padrao do delphi de celulas por outro qualquer

Top  Previous  Next

Question/Problem/Abstract:

 

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