[Lazarus] TSynEdit bug in destructor?

Bart bartjunk64 at gmail.com
Tue Nov 8 17:49:48 CET 2011


On 11/8/11, Mattias Gaertner <nc-gaertnma at netcologne.de> wrote:

> You should not free components while they process events.
> Use instead:
> Application.ReleaseComponent(Ed);
> This will free the component after the event.
>

I tried the following:


The PageControl which has/owns the TabSheet (which owns the SynEdit)
has a function
AddPage which creates the TabSheet and SynEdit on it, basically like this:

function TEditorPageControl.AddPage: TEditor;
var
  TS: TTabSheet;
  E: TEditor;
  PgIdx: Integer;
begin
  Result := nil;
  TS := TTabSheet.Create(Self);
  TS.PageControl := Self;
  PgIdx := TS.PageIndex;
  E := TEditor.Create(TS);  //<- TEditor is TSynEdit derived
  ActivePage := Pages[PgIdx];
end;

The function ClosePage which removes the TabSheet and SynEdit on it
basically does:

function TEditorPageControl.ClosePage(Index: Integer): Boolean;
var
  Cancel: Boolean;
  Pg: TTabSheet;
begin
  Result := False;
  if (Index > PageCount - 1) then Exit;
  Pg := Pages[Index];  //<-- Pg owns the SynEdit
  Cancel := False;
  if Assigned(FOnBeforeCloseEditor) then FOnBeforeCloseEditor(Pg, Cancel);
  if Not Cancel then
  begin
    Pg.PageControl := nil;
    Pg.Free;
    Result := True;
    if PageCount = 0 then InternalEditorStatusChange(nil, scAll);
  end;
end;

I then changed this into:

function TEditorPageControl.ClosePage(Index: Integer): Boolean;
var
  Cancel: Boolean;
  Pg: TTabSheet;
  Ed: TEditor;
begin
  Result := False;
  if (Index > PageCount - 1) then Exit;
  Pg := Pages[Index];  //<-- Pg owns the SynEdit
  Cancel := False;
  if Assigned(FOnBeforeCloseEditor) then FOnBeforeCloseEditor(Pg, Cancel);
  if Not Cancel then
  begin

    //newly added code
    Ed := EditorAtPage(Pg);  //<- returns the SynEdit in question
    Application.ReleaseComponent(Ed);
    Application.ProcessMessages;
    //end newly added code

    Pg.PageControl := nil;
    Pg.Free;
    Result := True;
    if PageCount = 0 then InternalEditorStatusChange(nil, scAll);
  end;
  Debugln('TEditorPageControl.ClosePage End.');
end;

This did not work, so I changed it into

function TEditorPageControl.ClosePage(Index: Integer): Boolean;
var
  Cancel: Boolean;
  Pg: TTabSheet;
  Ed: TEditor;
begin
  Result := False;
  if (Index > PageCount - 1) then Exit;
  Pg := Pages[Index];  //<-- Pg owns the SynEdit
  Cancel := False;
  if Assigned(FOnBeforeCloseEditor) then FOnBeforeCloseEditor(Pg, Cancel);
  if Not Cancel then
  begin

    Ed := EditorAtPage(Pg);  //<- returns the SynEdit in question
    Application.ReleaseComponent(Ed);
    Application.ProcessMessages;

    Pg.PageControl := nil;
    Application.ReleaseComponent(Pg);
    Application.ProcessMessages;

    Result := True;
    if PageCount = 0 then InternalEditorStatusChange(nil, scAll);
  end;
end;

I had to use Application.ReleaseComponent on both the SynEdit and the
TabSheet in order to get it to work.

Does this look OK?


>> Feauture or bug?
> By design. You should not free something that is in use.

That depends on the meaning of "in use" ;-)
I did not know it (the SynEdit) was actually doing something at all.
This code worked perfectly in Delphi 3.
It also works fine if the SynEdit is replaced by a Memo.

Thanks for the help.

Bart




More information about the Lazarus mailing list