Create a form and place a TValueListEditor
. Set the doColumnTitles
display option to False. Try and delete the first row. You will get a 'Grid Index out of Bounds'
error. It is an ugly pig and so I am here to ask if using a try except block is the only way to deal with it?
Background:
Row is inherited from TCustomGrid
via TCustomDrawGrid
(Line 493 VCL.grids.pas) The property getter is private variable FCurrent.Y
, the type of which is a value/field from a two value record. I cannot find where the FCurrent
value is set by default (so it integer defaults to 0). It is not clear what values exist if the TValueListEditor
has only one row and/or if there are no rows selected.
In any case, I get a Grid Index Out of Range Error - presumably raised from the TCustomGrid
- but only if there is only one row and/or I attempt a delete on the first row in the TValueListEditor
with doColumnTitles := false
. Delete on other rows is fine. Regardless of whether this is a bug or not it seems somewhat stupid and inconsistent.
Is there a reason why the TValueList
Editor constructor has inherited RowCount := 2;
?
The error is thrown by TValueListEditor.DeleteRow
according to:
try
if (Strings.Count = 0) or
(ARow < 1) or (ARow > RowCount - FixedRows) then
{$IF DEFINED(CLR)}
raise EInvalidGridOperation.CreateRes(SIndexOutOfRange);
{$ELSE}
raise EInvalidGridOperation.CreateRes(@SIndexOutOfRange);
{$ENDIF}
Strings.Delete(ARow - FixedRows);
finally
FDeleting := False;
end;
(See VCL.Valedit.pas at 804)
Is it a problem that there is an exception if (ARow < 1)
?
Otherwise, perhaps it is that FixedRows
is set in the constructor of the TCustomGrid
:
constructor TCustomGrid.Create(AOwner: TComponent);
const GridStyle = [csCaptureMouse, csOpaque, csDoubleClicks,
csNeedsBorderPaint, csPannable, csGestures];
begin
inherited Create(AOwner);
if NewStyleControls then
ControlStyle := GridStyle
else
ControlStyle := GridStyle + [csFramed];
FCanEditModify := True;
FColCount := 5;
FRowCount := 5;
FFixedCols := 1;
FFixedRows := 1;
...
and the comments in the header of VCL.grids.pas say "FixedRows The number of non-scrolling rows. This value must be at least one below RowCount."
(Line 138).
Methinks that there ends up being a problem with these values when the titles row is removed from the TValueListEditor
Anyway. My question is just - Does this require the use of an exception handler - or is there a more elegant way of un-kludging it?
Here is some basic no seatbelts code:
unit vleDebug;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Buttons, Vcl.StdCtrls, Vcl.Grids, Vcl.ValEdit;
type
TForm1 = class(TForm)
vleWhoCaresNerd: TValueListEditor;
Button1: TButton;
BitBtn1: TBitBtn;
Label1: TLabel;
Label2: TLabel;
procedure Button1Click(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
vleWhoCaresNerd.DeleteRow(vleWhoCaresNerd.Row);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
vGUID: TGUID;
begin
vleWhoCaresNerd.InsertRow('id', GUIDToString(vGUID), True);
end;
end.
Here's the .dfm:
object Form1: TForm1
Left = 0
Top = 0
Caption = ':P'
ClientHeight = 568
ClientWidth = 633
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -13
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 120
TextHeight = 16
object Label1: TLabel
Left = 295
Top = 162
Width = 242
Height = 16
Caption = 'Select and delete the first row if you dare.'
end
object Label2: TLabel
Left = 63
Top = 190
Width = 393
Height = 16
Caption =
'Delete other rows if you like. Make some with the Add GUID But' +
'ton.'
end
object vleWhoCaresNerd: TValueListEditor
Left = 8
Top = 8
Width = 617
Height = 145
DisplayOptions = [doAutoColResize, doKeyColFixed]
Strings.Strings = (
'jsonrpc=2.0')
TabOrder = 0
ColWidths = (
150
461)
end
object Button1: TButton
Left = 8
Top = 159
Width = 75
Height = 25
Caption = 'Add GUID'
TabOrder = 1
OnClick = Button1Click
end
object BitBtn1: TBitBtn
Left = 550
Top = 159
Width = 75
Height = 25
Caption = 'bbDelete'
TabOrder = 2
OnClick = BitBtn1Click
end
end