[Lazarus] Increasingly frustrated with DbGrids

Luca Olivetti luca at wetron.es
Wed Jun 22 12:18:04 CEST 2016

El 02/11/15 a les 11:56, Luca Olivetti ha escrit:
> El 02/11/15 a les 11:12, Luca Olivetti ha escrit:
>> Hello,
>> I constantly stumble with the behaviour of the TDBGrid.
>> I understand that it's a complex component, but every time I find an
>> issue an Luiz fixes it, two more pop up (or an older one resurfaces).
>> The latest episode of the saga is the futility of using a custom editor
>> (with OnSelectEditor), since the grids then sets the value of the field
>> using this snippet of code
>>    if (FEditor<>nil) and FEditor.Visible then begin
>>      Msg.LclMsg.msg:=GM_GETVALUE;
>>      Msg.grid:=Self;
>>      Msg.Col:=FCol;
>>      Msg.Row:=FRow;
>>      Msg.Value:=GetCells(FCol, FRow);
>>      FEditor.Dispatch(Msg);
>>      SetEditText(Msg.Col, Msg.Row, Msg.Value);
>>    end;
>> and this only works with the editors defined in Grids.pas, the only ones
>> managing the GM_GETVALUE message.
>> For other kinds of editors the result depends on how you move in the
>> grid: it could either maintain the value the editor set or reset it to
>> an empty string.
>> I think I will file a bug once I can create a simple project, but in the
>> meantime if somebody has an idea on how to solve it, it would be
>> appreciated.
> Bug created:
> http://bugs.freepascal.org/view.php?id=28944

As I said in the bug report I just discovered 
http://www.freepascal.org/~michael/articles/grids/grids.pdf (published 
in 2008!) describing how to correctly implement a custom editor (so the 
method from the wiki I originally used is wrong, I also added a note to 
the wiki).

*However* the component described by Michaƫl only works with a 
StringGrid, not with a DBGrid: when you change cell the grids sends the 
GM_SETVALUE message *before* the GM_GETVALUE one, so the edited value is 
lost and a semi-random one is used instead.

To make it work one has to override the Change method (as it is done in 

procedure TStringCellEditor.Change;
   {$IfDef DbgGrid} DebugLn('TStringCellEditor.Change INIT 
   inherited Change;
   if (FGrid<>nil) and Visible then begin
     FGrid.EditorTextChanged(FCol, FRow, Text);
   {$IfDef DbgGrid} DebugLn('TStringCellEditor.Change END');{$ENDIF}

*but* the EditorTextChanged method is protected, so an additional 
cracker class (ugly) has to be used, e.g.

TMyGrid = class(TCustomGrid)
   procedure EditorTextChanged(const aCol, aRow: Integer; const aText: 
string); override;

procedure TMyGrid.EditorTextChanged(const aCol, aRow: Integer;
   const aText: string);
   inherited EditorTextChanged(aCol, aRow, aText);

procedure TMyEditor.Change;
  if (FGrid<>nil) and Visible then begin
     TMyGrid(FGrid).EditorTextChanged(FCol, FRow, Text);

Maybe EditorTextChanged (and others methods to be used in custom 
editors) should be public?
Is there something else that I'm missing?

Luca Olivetti
Wetron Automation Technology http://www.wetron.es/
Tel. +34 93 5883004 (Ext.3010)  Fax +34 93 5883007

More information about the Lazarus mailing list