Recent

Author Topic: [SOLVED] TStringGrid and editor  (Read 2818 times)

spassigl

  • New Member
  • *
  • Posts: 25
[SOLVED] TStringGrid and editor
« on: January 31, 2021, 04:45:46 pm »
Hi

I have a problem with a custom TStringGrid. The Grid is created at runtime and the constructor is as follows:

Code: Pascal  [Select][+][-]
  1. constructor TMyGrid.Create(TheOwner: TComponent);
  2. begin
  3.    inherited Create(TheOwner);
  4.  
  5.    FixedCols := 0;
  6.    FixedRows := 0;
  7.  
  8.    GridLineWidth := 1;
  9.  
  10.    Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goEditing];
  11.    Options := Options + [goRowHighlight, goRowSelect];
  12.  
  13.    ScrollBars := ssAutoBoth;
  14.  
  15.    RowCount := 0;
  16.    ColCount := 2;
  17.  
  18.    with Columns.Add do
  19.    begin
  20.      ReadOnly := true;
  21.      Alignment := taRightJustify;
  22.      Color := clBtnFace;
  23.    end;
  24.    with Columns.Add do
  25.    begin
  26.      ReadOnly := false;
  27.      Alignment := taLeftJustify;
  28.    end;
  29.  
  30.    DefaultRowHeight := Font.GetTextHeight('Tg');
  31. end;

So far so good.
The problem is that when I select a cell for editing by pressing the Enter key, the editor shows up correctly, but the text is fully selected and cannot use the lef and right keys to move within the editor. Infact, if I use those keys the grid selects another cell (left or right of that one).

If I instead click on the selected editor text all goes well and I can move around the text in the editor.

Also: if I press enter on a cell to edit it, the OnEditingDone event is fired twice: at the beginning of the edit and at the end. If, instead, I click the cell to edit it, OnEditingDone is (correctly) fired once, i.e. at the end of the edit.

Is there anything I'm missing here?

Thanks
« Last Edit: January 31, 2021, 06:37:30 pm by spassigl »

wp

  • Hero Member
  • *****
  • Posts: 12902
Re: TStringGrid and editor
« Reply #1 on: January 31, 2021, 05:24:28 pm »
This is a limitation of the LCL TStringGrid. In fact, it is an incomatibility with Delphi and should be fixed. Somebody needs to write a bug report.

You can work around by entering edit mode only by pressing F2 twice. The first F2 shows the editor, but the entire text is selected, the second F2 keeps the editor but removes the selection. Or you can enter edit mode by two clicks.

You can save one F2 press or one mouse click when you activate AlwaysShowEditor in the grid's options.

jamie

  • Hero Member
  • *****
  • Posts: 6988
Re: TStringGrid and editor
« Reply #2 on: January 31, 2021, 06:04:25 pm »
I am sure there is some flag lurking in there somewhere...
but here is a work around....

Code: Pascal  [Select][+][-]
  1. procedure TForm1.StringGrid1KeyDown(Sender: TObject; var Key: Word;
  2.   Shift: TShiftState);
  3. begin
  4.  if Sender is TstringGrid then with TstringGrid(Sender) do
  5.  Begin
  6.    if Editor is TStringCellEditor Then
  7.     Begin
  8.       if (TEdit(Editor).Sellength <> 0)and(Key= VK_Left) Then
  9.         TEDit(Editor).Sellength := 0;
  10.     end;
  11.  end;
  12. end;                                                  
  13.  

Include the lclType unit for the key defines
The only true wisdom is knowing you know nothing

spassigl

  • New Member
  • *
  • Posts: 25
Re: TStringGrid and editor
« Reply #3 on: January 31, 2021, 06:14:28 pm »
I had tried that already but I'd get an Invalid Type Cast exception.


I am sure there is some flag lurking in there somewhere...
but here is a work around....

Code: Pascal  [Select][+][-]
  1. procedure TForm1.StringGrid1KeyDown(Sender: TObject; var Key: Word;
  2.   Shift: TShiftState);
  3. begin
  4.  if Sender is TstringGrid then with TstringGrid(Sender) do
  5.  Begin
  6.    if Editor is TStringCellEditor Then
  7.     Begin
  8.       if (TEdit(Editor).Sellength <> 0)and(Key= VK_Left) Then
  9.         TEDit(Editor).Sellength := 0;
  10.     end;
  11.  end;
  12. end;                                                  
  13.  

Include the lclType unit for the key defines

jamie

  • Hero Member
  • *****
  • Posts: 6988
Re: TStringGrid and editor
« Reply #4 on: January 31, 2021, 06:21:13 pm »
it compiles and runs fine here.

what Laz version do you have ?

The only true wisdom is knowing you know nothing

wp

  • Hero Member
  • *****
  • Posts: 12902
Re: TStringGrid and editor
« Reply #5 on: January 31, 2021, 06:23:27 pm »
The line of inheritance is

TStringCellEditor --> TCustomMaskEdit --> TCustomEdit
TEdit --> TCustomEdit

This means that TStringCellEditor is not a descendant of TEdit. Why don't you cast to TStingCellEditor?

jamie

  • Hero Member
  • *****
  • Posts: 6988
Re: TStringGrid and editor
« Reply #6 on: January 31, 2021, 06:26:47 pm »
Well it works fine for me here because there exist at the base a TEDIT where these properties are.

I did this with an older version of laz with 3.0.4 but I don't see where this has changed any in current state.
The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 6988
Re: TStringGrid and editor
« Reply #7 on: January 31, 2021, 06:30:09 pm »
Ok, a remapped version
Code: Pascal  [Select][+][-]
  1. procedure TForm1.StringGrid1KeyDown(Sender: TObject; var Key: Word;
  2.   Shift: TShiftState);
  3. begin
  4.  if Sender is TstringGrid then with TstringGrid(Sender) do
  5.  Begin
  6.    if Editor is TStringCellEditor Then with Editor As TStringCellEditor do
  7.     Begin
  8.      If  (Sellength <> 0)and(Key= VK_Left) Then
  9.         Sellength := 0;
  10.     end;
  11.  end;
  12. end;                          
  13.  
  14.  

Works either way for me..
The only true wisdom is knowing you know nothing

spassigl

  • New Member
  • *
  • Posts: 25
Re: TStringGrid and editor
« Reply #8 on: January 31, 2021, 06:31:12 pm »
2.0.10
FPC 3.2.0

On Linux/GTK

This is what I had done.
Casting to TStringCellEditor doesn't work, either. I had also tried TCustomMaskEdit to no avail.

Code: Pascal  [Select][+][-]
  1. procedure TMyGrid.MyGridKeyDown(Sender: TObject; var Key: Word;
  2.    Shift: TShiftState);
  3. begin
  4.    case Key of
  5.      VK_LEFT, VK_RIGHT:
  6.          if Editor is TStringCellEditor then
  7.           begin
  8.                if (TEdit(Editor).Sellength <> 0) then
  9.                  TEdit(Editor).SelLength := 0;
  10.           end;
  11.       VK_DELETE:
  12.          if ssCtrl in Shift then
  13.          begin
  14.             DeleteRow(Row);
  15.             Key := 0;
  16.          end;
  17.    end; // case
  18. end;
  19.  
  20. constructor TMyGrid.Create(TheOwner: TComponent);
  21. begin
  22.    inherited Create(TheOwner);
  23.  
  24.    [Additional setup omitted]
  25.  
  26.    OnKeyDown   := @MyGridKeyDown;
  27. end;
  28.  


it compiles and runs fine here.

what Laz version do you have ?

it compiles and runs fine here.

what Laz version do you have ?

spassigl

  • New Member
  • *
  • Posts: 25
Re: TStringGrid and editor
« Reply #9 on: January 31, 2021, 06:33:24 pm »
Nope it doesn't work for me.


Ok, a remapped version
Code: Pascal  [Select][+][-]
  1. procedure TForm1.StringGrid1KeyDown(Sender: TObject; var Key: Word;
  2.   Shift: TShiftState);
  3. begin
  4.  if Sender is TstringGrid then with TstringGrid(Sender) do
  5.  Begin
  6.    if Editor is TStringCellEditor Then with Editor As TStringCellEditor do
  7.     Begin
  8.      If  (Sellength <> 0)and(Key= VK_Left) Then
  9.         Sellength := 0;
  10.     end;
  11.  end;
  12. end;                          
  13.  
  14.  

Works either way for me..

wp

  • Hero Member
  • *****
  • Posts: 12902
Re: TStringGrid and editor
« Reply #10 on: January 31, 2021, 06:34:10 pm »
Better to study the source code: In TStringCellEditor.KeyDown for VK_LEFT and VK_RIGHT, there is

Code: Pascal  [Select][+][-]
  1.       if GetFastEntry then begin
  2.         IntSel:=
  3.           ((Key=VK_LEFT) and not AtStart) or
  4.           ((Key=VK_RIGHT) and not AtEnd);
  5.       if not IntSel then begin
  6.           doGridKeyDown;

This "GetFastEntry" looks interesting: A "Ctrl-Click" on it moves the source editor to this procedure:

Code: Pascal  [Select][+][-]
  1.   function GetFastEntry: boolean;
  2.   begin
  3.     if FGrid<>nil then
  4.       Result := FGrid.FastEditing
  5.     else
  6.       Result := False;
  7.   end;

And here we have a FGrid.FastEditing. I suppose that "Fast" is understood here as a method to type text into a cell, press the right-arrow to move to the next cell and continue typing there. In Delphi however the cursor does not move out of the cell when Left/right is pressed.

What if we set FastEditing to false -- it is a public property of TCustomDrawGrid, the ancestor of TStringGrid. Voila - we have the Delphi behaviour.

So, all you have to do, is to set FastEditing to false in your grid constructor.

P.S.
It's even mentioned in the Grids wiki: https://wiki.lazarus.freepascal.org/Grids_Reference_Page#Ways_in_which_you_can_make_a_Lazarus_grid_more_Delphi-compatible

« Last Edit: January 31, 2021, 06:39:15 pm by wp »

spassigl

  • New Member
  • *
  • Posts: 25
Re: TStringGrid and editor
« Reply #11 on: January 31, 2021, 06:37:19 pm »
That fixed it!

Thanks!

jamie

  • Hero Member
  • *****
  • Posts: 6988
Re: [SOLVED] TStringGrid and editor
« Reply #12 on: January 31, 2021, 07:17:50 pm »
@Wp

 I consider the fastEditing an undesirable feature with absolutely no idea of what it's good for other then causing bugs.

 why isn't this set to false by default ? and why isn't it a published property ?

The only true wisdom is knowing you know nothing

wp

  • Hero Member
  • *****
  • Posts: 12902
Re: [SOLVED] TStringGrid and editor
« Reply #13 on: January 31, 2021, 07:43:15 pm »
Don't ask me...

 

TinyPortal © 2005-2018