The Delphi Bug List

Visual Component Library (VCL)

Additional


The color codes indicate in which version(s) of Delphi the bug occurs and what its status is.
Latest update: 19 January 1999
Bug # Delphi versions Description
20 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TCheckListBox
There is a memory leak in TCheckListBox when calling GetItemData
33 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TCustomGrid
TCustomGrid unnecessarily shows scrollbars
34 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TCustomGrid
MoveColRow method's final parameter "Show" has no effect
35 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TCustomGrid
Descendant components cause run-time error 210.
48 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TImage
TImage causes memory leak.
61 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TMaskEdit
On some computer/keyboard combinations, TMaskEdit causes a keyboard lock or a big slowdown and a blinking numlock.
62 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TMaskEdit
This control will not correctly process ENTER and ESC keys in dialogs.
63 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TMaskEdit
Some mask characters are not properly handled if specified as literal characters.
104 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TNoteBook
Deleting the first page of a TNoteBook gets you in trouble.
81 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TSpeedButton
OnDblClick Event is never called if AllowAllUp = true.
85 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TStringGrid
See also TCustomGrid
86 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TStringGrid
TStringGrid's Cursor won't move at Shift-TAB
87 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TStringGrid
Calling Insert and Delete methods of Cols and Rows properties gives Error 210.
88 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TStringGrid
Bug in TStringGrid with goRowSelection
89 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TStringGrid
TStringGrid needs string content to store object data
406 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TStringGrid
If any TabStops[col] are set to False but no non-default ColumnWidths are set in a TDrawGrid/TStringGrid and the ColumnCount is increased, random tab stops result and, store overwriting and GPFs could occur.
407 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 TStringGrid
If the last row height (column width, tab stop) of a TDrawGrid/TStringGrid is not equal to the DefaultRowHeight (DefaultColWidth, True) and the number of rows (columns) is increased, the height of that row (width of that column, tabstop) gets set to the default.

Bug #20; last modified: before April 1998
1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
N/A N/A Unknown Unknown Unknown Unknown Unknown Unknown
Additional - TCheckListBox

There is a memory leak in TCheckListBox when calling GetItemData

Description
Reported by Edgar Vorland; checked by Erik Sperling Johansen
The problem is that the wrapper created when setting CheckListBox.Items.Objects[n] is not destroyed unless you explicitly call CheckListBox.Items.Clear before the checklistbox is destroyed.

Bug #33; last modified: before April 1998
1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
Exists Exists Exists Unknown Unknown Unknown Unknown Unknown
Additional - TCustomGrid

TCustomGrid unnecessarily shows scrollbars

Description
Reported by Mike Cariotoglou; checked and edited by Stefan Hoffmeister
The VCL code for detecting the presence of scrollbars in a TCustomGrid relies on the (documented!) behaviour that the Windows API routine GetScrollRange will return 0 for both the upper and lower range of the scrollbar if the scrollbar is invisible. While under Windows 3.1 this is the case, at least Windows 95 does NOT work according to the (Win32 API) documentation. This will make the VCL think that scrollbars are visible while in fact they are not. The result is a grid showing scrollbars though none are needed.
The behaviour can be easily seen at design time (running at least on a Windows 95 system):
  • Drop a TStringGrid onto a form
  • Resize the grid so that no room is left in the client area (make it look as if the cells completely fill the client area without letting scrollbars show)
  • Toggle the BorderStyle property
  • You will notice that scrollbars have appeared although there is enough room for all cells in the grid. This gets worse at runtime, as a perfectly (i.e. without scrollbars) sized grid WILL suddenly have scrollbars at runtime.
    Solution / workaround
    Due to an incompatibility between Windows 3.1 and Windows 95 a different mechanism to detect the presence of scrollbars has to be employed. In the VCL source code of GRIDS.PAS completely replace the local function ScrollBarVisible in TCustomGrid.UpdateScrollRange with the following code:
      function ScrollBarVisible(Code: Word): Boolean;
      var
        Min, Max: Integer;
      begin
        Result := False;
        case Code of
          sb_Horz:
            if (Scrollbars = ssBoth) or
               (Scrollbars = ssHorizontal) then
              Result := (GetWindowLong(Handle, gwl_Style) and WS_HSCROLL) <> 0;
          sb_Vert:
            if (Scrollbars = ssBoth) or
               (Scrollbars = ssVertical) then
              Result := (GetWindowLong(Handle, gwl_Style) and WS_VSCROLL) <> 0;
        end;
      end;

    Bug #34; last modified: before April 1998
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    Exists Fixed Fixed Fixed Fixed Fixed Fixed Fixed
    Additional - TCustomGrid

    MoveColRow method's final parameter "Show" has no effect

    Description
    MoveColRow is declared as follows:
    TCustomGrid.MoveColRow(ACol, ARow: Longint; MoveAnchor, Show: Boolean);
    Contrary to CWG, the final parameter "show" has no effect (because MoveColRow directly calls the private MoveCurrent (same parameters), which does not use its last parameter).

    Bug #35; last modified: before April 1998
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    Gotcha Fixed Fixed Fixed Fixed Fixed Fixed Fixed
    Additional - TCustomGrid

    Descendant components cause run-time error 210.

    Description
    Creating a descendant component from TCustomGrid will cause a RTE 210 when you drop the new component onto a form.
    Solution / workaround
    This is not actually a VCL bug, as there is nothing wrong with the code. The problem lies in Delphi's handling of abstract methods. The real error is that TCustomGrid has a method called DrawCell that is responsible for drawing each cell in the grid. Because a TCustomGrid neither knows nor assumes anything about how you want the data to appear, it implements DrawCell as an abstract method, meaning you MUST override it in descendant components. The real problem here is that the documentation for TCustomGrid.DrawCell does not point this out, and crashing Delphi with an RTE 210 does not help matters at all. To worsen the situation, the documentation for a RTE 210 (and all runtime errors) is listed only in the Object Pascal Language Guide, which you must purchase separately from Borland. However, you can obtain a free electronic copy of this manual in Acrobat Reader format from Borland's FTP site ( objlang.zip ~ 2MB).
    Add this to your TCustomGrid descendant to prevent the RTE 210 error:
    protected
      { Protected declarations }
      procedure DrawCell(ACol, ARow: Longint; 
                         ARect: TRect; AState: TGridDrawState); override;
    
    { ..... }
    
    procedure TMyGrid.DrawCell(ACol, ARow: Longint; 
                               ARect: TRect; AState: TGridDrawState);
    begin
      { Print Column, Row in each cell }
      Canvas.TextOut(ARect.Left, ARect.Top, IntToStr(ACol)+', '+IntToStr(ARow));
    end;

    Bug #48; last modified: before April 1998
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    Exists Fixed Fixed Fixed Fixed Fixed Fixed Fixed
    Additional - TImage

    TImage causes memory leak.

    Description
    Reported by Rolf Peder Klemetsen and Ray Lischner
    (RPK:) There is a bug in Delphi 1.0 that causes a memory leak when using the TImage component with bitmaps that have a size which is a multiple of 64KB (e.g 768 X 512 with 256 colors). Delphi 2.0 does not have the same bug.
    (RL:) This is a known problem with any graphical image whose data size is an integral multiple of 64K.
    Solution / workaround
    By Ray Lischner
    The solution is to edit Graphics.pas. Look for all the uses of MemAlloc. Change the FreeMem calls that free the MemAlloc-ed memory to use MemFree:
    procedure MemFree(Ptr: Pointer; Size: LongInt);
    begin
      if Size > $FFFF then
        GlobalFreePtr(Ptr)
      else
        FreeMem(Ptr, Word(Size))
    end;

    Bug #62; last modified: before April 1998
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha
    Additional - TMaskEdit

    This control will not correctly process ENTER and ESC keys in dialogs.

    Description
    Reported by Jack Bakker
    See also TSpinEdit, which has the same problem, but the solution given there doesn't work for TMaskEdit
    If a TMaskEdit control has focus in a dialog, pressing ESC will not cancel the dialog (if there is a cancel button), and pressing ENTER will not process the default button (if there is a default button). Standard UI for Windows dialogs dictates that the ENTER be treated as the OK button and ESC as the Cancel button. TMaskEdit prevents this behavior.
    Solution / workaround
    By Arjen Broeze

    This behavior is by design. The MaskEdit component treats the ENTER key as the validate key (input is checked for validity) and the ESC key as the reset key (input is cleared and mask restored). The MaskEdit component gets these messages because it handles the WM_GETDLGCODE windows message (Delphi 1.0, Delphi 2.0's MaskEdit handles the CM_WANTSPECIALKEY message).

     Solution:
    If you would like the MaskEdit to behave like any other component, either modify the WMGetDlgCode method of the TCustomMaskEdit component in the VCL source code or create a descendant component that handles the WMGetDlgCode differently, like in the following example:

    type TMyMaskEdit = class(TMaskEdit)
      protected
        procedure wmGetDlgCode(Var Msg: TWMGetDlgCode); message WM_GETDLGCODE;
      end;
    
    procedure TMyMaskEdit.wmGetDlgCode(var Msg: TWMGetDlgCode);
    begin
      { do not call inherited message handler, instead specify wanted keys here }
      Msg.Result := DLGC_HASSETSEL or DLGC_WANTARROWS or DLGC_WANTCHARS;
    end;

    Bug #63; last modified: before April 1998
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    Exists Exists Exists Unknown Unknown Unknown Unknown Unknown
    Additional - TMaskEdit

    Some mask characters are not properly handled if specified as literal characters.

    Description
    The / and : characters are not displayed correctly when they are specified as literal characters (prefaced by a \ character). The / character is normally interpreted as the date separator (as in 05/30/95) and : as the time separator (as in 12:39:30). These characters are determined by the international settings of Control Panel. Because most US users have their date separator set to /, they will not notice that specifying \/ does not truly insert a / character. The same is true for the \: combination.

    To see the problem, start the International applet in Control Panel. Choose the Change button for Date Format. Enter any character other than / as the Separator. Close the International applet completely, as changes will not take effect until you do. Now try a TMaskEdit control that has "99\/99\:99" for it's EditMask property. According to documentation, the edit control with data in it should look like "34/12:32", but it really discards the \ literal specifier and uses the international settings, the same as it would if you had not given the literal at all. This problem is especially bad for applications that will be used outside of the US, which is becoming common with shareware programs distributed via the Internet.

    Solution:

    There is no solution known at this time short of fixing the bug in the VCL source code. I have not had time to do this, so cannot advise on how to. If anyone knows of a work-around, or has fixed the VCL source, please send it to me so that it can be published here.


    Bug #104; last modified: before April 1998
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    Exists Exists Unknown Unknown Unknown Unknown Unknown Unknown
    Additional - TNoteBook

    Deleting the first page of a TNoteBook gets you in trouble.

    Description
    Imagine a TNotebook with only two pages, "First" and "Second", in this order. "First" is the currently active page, i.e. TNotebook.PageIndex = 0. Delete this page: Notebook1.Pages.Delete(0).

    One would think that "Second", now the only page left becomes the active and visible page. This is not the case.
    Trying to switch to this page to make it visible by specifying TNotebook.ActivePage := "Second" will fail, so that in this setting there is *no* way to activate this page.
    The reason for this behaviour is explained by Ray Lischner:
    The bug is that when you delete any page from a TNotebook, it automatically sets the PageIndex to 0. But when it sets the PageIndex, it has an "optimization" that if the PageIndex is not changing, it does not do anything.
    Thus, if PageIndex is 0 to start with (namely, "First"), and we call Pages.Delete(0) to delete "First", the TNotebook object sets PageIndex to 0 (which is now "Second"), but since PageIndex was already 0, it thinks it is already displaying the correct page, and so does not do anything.
    Solution / workaround
    Workaround: Set TNotebook.PageIndex to 1 before deleting the *first* page.

    Bug #81; last modified: 25-Oct-98
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    Exists Exists Exists Exists Exists Exists Exists Unknown
    Additional - TSpeedButton

    OnDblClick Event is never called if AllowAllUp = true.

    Description
    ; checked by Erik Berry
    If a TSpeedButton is used with AllowAllUp = True it will not fire the OnDblClick event.

    Erik Berry added to this (22 Oct 98):
    In fact, OnDblClick is never called, regardless of the value of AllowAllUp

    Solution / workaround
    You can modify the VCL source code for BUTTONS.PAS:
    procedure TSpeedButton.WMLButtonDblClk(var Message: TWMLButtonDown);
    begin
      inherited;
      {$IFDEF FixSpeedButtonDblClick}
        DblClick;
      {$ELSE}
        if FDown then DblClick;
      {$ENDIF}
    end;
    This is the preferred solution as it avoids adding irritating logic in case of the workaround below.
    Alternatively you can work around the problem by adding logic to the OnMouseDown event:
    procedure TForm1.SpeedButton1DblClick(Sender: TObject);
    begin
      ShowMessage('Double-Click');
    end;
    
    procedure TForm1.SpeedButton1MouseDown(Sender: TObject; 
      Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    begin
      if (Button = mbLeft) and (ssDouble in Shift) then
        SpeedButton1DblClick(Sender);
       { continued processing }
    end;

    Bug #86; last modified: before April 1998
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    N/A Unknown Exists Unknown Unknown Unknown Unknown Unknown
    Additional - TStringGrid

    TStringGrid's Cursor won't move at Shift-TAB

    Description
    Reported by Raymond Wilson; checked and edited by Erik Sperling Johansen
    Basically if you have a column which you have set up so that tab will not stop in that column, and you position the cursor in a cell in the column immediately to the right of that column and press SHIFT-TAB, then the cursor stays in the current cell. If you have the cursor in a cell immediately to the left of the tab-stopped column and press TAB then the cursor correctly skips over the column.
    This is caused by a bug in the KeyDown method of TCustomGrid. Essentially after moving one column to the left on SHIFT-TAB, the shift status for the keypress is cleared, causing the logic to move the cursor to the right again.
    Reproduce by:
  • Add a stringgrid to a form and set its Options to include goTabs.
  • In OnCreate of the form, set StringGrid1.TabStops[2] := TRUE.
  • Run the application, move to column 3 of the grid and press shift+tab, which does not cause any visible changes
  • Solution / workaround
    Fix:
    in Delphi 3\Source\VCL\Grids.pas, locate line 2940.
      Shift := [];
    Move this to line 2955,
        end;
      Shift := [];
      MaxTopLeft.X := ColCount - 1;
    Notes from checker:
    This fix could cause problems if you in a descendant of TStringGrid overrides the KeyDown method and does something like this:
      inherited;
      if ssShift in Shift then
        DoSomething;
    This expression will never be true using the above fix. A better solution might be to replace line 2940 of grids.pas with this:
      if TabStops[NewCurrent.X] or (NewCurrent.X = FCurrent.X)
      then Shift := [];

    Bug #87; last modified: before April 1998
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    Exists Unknown Unknown Unknown Unknown Unknown Unknown Unknown
    Additional - TStringGrid

    Calling Insert and Delete methods of Cols and Rows properties gives Error 210.

    Description
    The Cols and Rows properties of a TStringGrid are of the TStrings class and have Insert and Delete methods. Calling these methods gives error 210. The exact cause for this has not yet been found.
    Solution / workaround
    If you want to insert a cell, you can Assign a row (or column) to a TStringList, then insert the cell and then Assign it back to the row.
    To prevent loss of the last cell value, one can increment the ColCount (or RowCount) value beforehand.

    Bug #88; last modified: before April 1998
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    Exists Fixed Fixed Fixed Fixed Fixed Fixed Fixed
    Additional - TStringGrid

    Bug in TStringGrid with goRowSelection

    Description
    Reported by Lorin (surname?); checked by Stefan Hoffmeister
    Drop a TStringGrid on a form, enable goRowSelection item in the Options property. Run the program and try to select a row. You will notice that a range of columns is selected.
    This behaviour is caused by an error in GRIDS.PAS, procedure TCustomGrid.MoveAnchor
    Solution / workaround
    It seems as if the only solution to fix this problem is to modify the VCL source code:
    procedure TCustomGrid.MoveAnchor(const NewAnchor: TGridCoord);
    var
      OldSel: TGridRect;
    begin
      if [goRangeSelect, goEditing] * Options = [goRangeSelect] then
      begin
        OldSel := Selection;
        FAnchor := NewAnchor;
    
    {$IFDEF FixRowSelectBug}
        if goRowSelect in Options then FAnchor.X := ColCount - 1;
    {$ELSE}
        if goRowSelect in Options then FAnchor.Y := ColCount - 1;
    {$ENDIF}
    
        ClampInView(FAnchor);
        SelectionMoved(OldSel);
      end
      else MoveCurrent(NewAnchor.X, NewAnchor.Y, True, True);
    end;

    Bug #89; last modified: 25-Oct-98
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    Exists Unknown Unknown Unknown Unknown Unknown Fixed Fixed
    Additional - TStringGrid

    TStringGrid needs string content to store object data

    Description
    Reported by Wim de Winter; analysis by Stefan Hoffmeister
    TStringGrid throws an exception if the .Objects property is assigned before the corresponding .Cells property has been assigned a **non-empty** string value. Reproduce this problem using this code:
  • Create a new form with a TStringGrid and two buttons.
  • Add two buttons with the following event handlers:
  • procedure TForm1.BitBtn1Click(Sender: TObject);
    begin
      { this will cause the problem }
      StringGrid1.Cells[1, 1]   := '';
      StringGrid1.Objects[1, 1] := TObject.Create;
    end;
    
    procedure TForm1.BitBtn2Click(Sender: TObject);
    begin
      StringGrid1.Cells[1, 1]   := 'Any text';
      StringGrid1.Objects[1, 1] := TObject.Create;
    end;
  • Run the program and click...
  • The root of the problem is this code in GRIDS.PAS:
    procedure TStringSparseList.PutObject(Index: Integer; AObject: TObject);
    var
      p: PStrItem;
    begin
      p := PStrItem(FList[Index]);
      if p <> nil 
      then p^.FObject := AObject 
      else if AObject <> nil 
           then Error;
      Changed
    end;
    Here the developer simply raises an exception since no non-empty string item has been assigned yet.
    Solution / workaround
    A work-around is to first assign a non-empty string - a single space is sufficient.
    A fix in the Delphi 1.02 VCL source code would be (compare with TStringSparseList.Put):
    procedure TStringSparseList.PutObject(Index: Integer; AObject: TObject);
    var
      p: PStrItem;
    begin
      p := PStrItem(FList[Index]);
      if p <> nil then
        p^.FObject := AObject
      else 
      if AObject <> nil then
    {$IFDEF FixEmptyCellBug}
        FList[Index] := NewStrItem('', AObject);
    {$ELSE}
        Error;
    {$ENDIF}
      Changed;
    end;

    Bug #406; last modified: 13-Aug-98
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    Exists Exists Exists Exists Exists Exists Exists Unknown
    Additional - TStringGrid

    If any TabStops[col] are set to False but no non-default ColumnWidths are set in a TDrawGrid/TStringGrid and the ColumnCount is increased, random tab stops result and, store overwriting and GPFs could occur.

    Description
    Reported by Chris Cheney; checked by Reinier Sterkenburg
    To reproduce the problem:
    procedure TForm1.FormCreate(Sender: TObject);
    const
      Gap = 100;
    
      procedure SetupStringGrid(SG: TStringGrid; TheTop: Integer);
      begin
        with SG do
          begin
            Left := 0;
            Width := Self.ClientWidth;
            Top := TheTop;
            Height := (Self.ClientHeight - Gap) div 2;
            TabStops[0] := False { this causes the TabStops array to be built }
          end;
      end;
    
    begin
      { set the form to make use of the full screen width and height }
      Left := 0;
      Width := Screen.Width;
      Top := 0;
      Height := Screen.Height;
      { set the stringgrids to be able to use the full width available }
      SetupStringGrid(StringGrid1, Gap); { allow gap at top }
      SetupStringGrid(StringGrid2, StringGrid1.Top + StringGrid1.Height);
      { StringGrid2 only: causes ColWidths array to be built }
      StringGrid2.ColWidths[0] := 50
    end;
    
    procedure TForm1.FormClick(Sender: TObject);
    begin
      with StringGrid1 do ColCount := ColCount + 1;
      with StringGrid2 do ColCount := ColCount + 1;
      FormShow(Sender)
    end;
    
    procedure TForm1.FormShow(Sender: TObject);
    var
      I: Integer;
    begin
      with StringGrid1 do for I := 0 to ColCount - 1 do
        Cells[I, 0] := Format('%d', [Ord(TabStops[I])]);
      with StringGrid2 do for I := 0 to ColCount - 1 do
        Cells[I, 0] := Format('%d', [Ord(TabStops[I])]);
    end;
    Solution / workaround
    To fix the problem, in DoChange, replace the sequence
        if FColWidths <> nil then
        begin
          UpdateExtents(FColWidths, ColCount, DefaultColWidth);
          UpdateExtents(FTabStops, ColCount, Integer(True));
        end;
    with
        if FColWidths <> nil then
          UpdateExtents(FColWidths, ColCount, DefaultColWidth);
        if FTabStops <> nil then
          UpdateExtents(FTabStops, ColCount, Integer(True));
    A workaround would be to explicitly set ColWidth[0] so that the array pointed to by FColWidths exists; one must also ensure that this is done after any setting of DefaultColumnWidth as this will clear out the ColWidths array.

    Bug #407; last modified: 24-Jul-98
    1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02
    Exists Exists Exists Exists Exists Fixed Fixed Fixed
    Additional - TStringGrid

    If the last row height (column width, tab stop) of a TDrawGrid/TStringGrid is not equal to the DefaultRowHeight (DefaultColWidth, True) and the number of rows (columns) is increased, the height of that row (width of that column, tabstop) gets set to the default.

    Description
    Reported by Chris Cheney; checked by Reinier Sterkenburg
    To reproduce the problem:
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      { set up the form to use the full screen width and height }
      Left := 0;
      Top := 0;
      Width := Screen.Width;
      Height := Screen.Height;
    
      with StringGrid1 do
        begin
          { position the StringGrid }
          Left := 0;
          Top := 100; { leave somewhere to click to activate OnFormClick event }
          Width := Self.ClientWidth;
          Height := Self.ClientHeight - Top;
           { set to demonstrate Colwidths, RowHeights, and TabStops bugs }
          ColWidths[ColCount - 1] := 2 * DefaultColWidth;
          RowHeights[RowCount - 1] := 2 * DefaultRowHeight;
          TabStops[ColCount - 1] := False
        end
    end;
    
    procedure TForm1.FormClick(Sender: TObject);
    begin
      with StringGrid1 do
        begin
          ColCount := ColCount + 1; { incorrectly changes ColWidths & TabStops }
          RowCount := RowCount + 1  { incorrectly changes RowHeights }
        end;
      FormShow(Sender)
    end;
    
    procedure TForm1.FormShow(Sender: TObject);
    var
      I: Integer;
    begin
      { show TabStops value for each column }
      with StringGrid1 do for I := 0 to ColCount - 1 do
        Cells[I, 0] := Format('%d', [Ord(TabStops[I])]);
    end;
    This is a bug because the row height (column width, tab stop) should not be changed when the number rows (columns) is increased; in the program above, the row height, column width, tab stop of the previously last (5th) row and column should remain what they were set to (double the height/width of the others, 0 (false) respectively).

    Windows 3.1/Windows for WorkGroups 3.11 - both with Win32s

    Solution / workaround
    In the VCL GRIDS.PAS ModifyExtents procedure (which is used indirectly by TCustomGrid), the line
       I := Index;
    should be
       I := Index + 1;
    to take account of the Extents array being offset by 1 to allow for the zeroth element being used to store the size.

    A workaround would be:
    Before increasing the number of rows (columns), save the height (width, tab stop) of the last row (column) and, afterwards, if that height (width, tabstop) differs from the default, set the height (width, tabstop) to the saved value(s).


    Index page
    The Delphi Bug Lists are maintained by Reinier Sterkenburg, with help from the DeBug Team.
    All feedback is appreciated. See also the feedback section of the Delphi Bug List home page.